跳转至

三角剖分

模版
代码
C++
{ 计算几何基础 }
struct Edge {
    int idx;
    list<Edge>::iterator nxt;
    Edge(int idx = 0) : idx(idx) {}
};
list<Edge> head[100005];
int idx[100005], n;
vector<pair<Point, int>> points;
void addEdge(int u, int v) {
    head[u].emplace_front(v);
    head[v].emplace_front(u);
    begin(head[u]) -> nxt = begin(head[v]);
    begin(head[v]) -> nxt = begin(head[u]);
}
void Delaunay(int L, int R) {
    if (R - L < 3) {
        for (int i = L ; i <= R ; i++) {
            for (int j = i + 1 ; j <= R ; j++) {
                addEdge(i, j);
            }
        }
        return;
    }
    int mid = L + R >> 1;
    Delaunay(L, mid);
    Delaunay(mid + 1, R);
    int _L = L, _R = R;
    for (bool up = true ; up ; ) {
        up = false;
        Point pL = points[_L].first, pR = points[_R].first;
        for (auto it = begin(head[_L]) ; it != end(head[_L]) ; it++) {
            Point t = points[it -> idx].first;
            int res = sgn(cross(pR, pL, t));
            if (res > 0 || (res == 0 && sgn(distance(pR, t) - distance(pR, pL)) < 0)) {
                _L = it -> idx;
                up = true;
                break;
            }
        }
        if (up) continue;
        for (auto it = begin(head[_R]) ; it != end(head[_R]) ; it++) {
            Point t = points[it -> idx].first;
            int res = sgn(cross(pL, pR, t));
            if (res < 0 || (res == 0 && sgn(distance(pL, t) - distance(pL, pR)) < 0)) {
                _R = it -> idx;
                up = true;
                break;
            }
        }
    }
    addEdge(_L, _R);
    while (true) {
        Point pL = points[_L].first, pR = points[_R].first;
        int ch = -1, side = 0;
        for (auto it = begin(head[_L]) ; it != end(head[_L]) ; it++) {
            if (sgn(cross(pL, pR, points[it -> idx].first)) > 0 && (ch == -1 || pointCircleRelation(points[it -> idx].first, Circle(pL, pR, points[ch].first)) == 0)) {
                ch = it -> idx;
                side = -1;
            }
        }
        for (auto it = begin(head[_R]) ; it != end(head[_R]) ; it++) {
            if (sgn(cross(pR, points[it -> idx].first, pL)) > 0 && (ch == -1 || pointCircleRelation(points[it -> idx].first, Circle(pL, pR, points[ch].first)) == 0)) {
                ch = it -> idx;
                side = 1;
            }
        }
        if (ch == -1) break;
        if (side == -1) {
            for (auto it = begin(head[_L]) ; it != end(head[_L]) ; it++) {
                if (lineCrossRelation(Line(pL, points[it -> idx].first), Line(pR, points[ch].first)) == 2) {
                    head[it -> idx].erase(it -> nxt);
                    head[_L].erase(it);
                }
            }
            _L = ch;
            addEdge(_L, _R);
        } else {
            for (auto it = begin(head[_R]) ; it != end(head[_R]) ; it++) {
                if (lineCrossRelation(Line(pR, points[it -> idx].first), Line(pL, points[ch].first)) == 2) {
                    head[it -> idx].erase(it -> nxt);
                    head[_R].erase(it);
                }
            }
            _R = ch;
            addEdge(_L, _R);
        }
    }
}
vector<pair<int, int>> getEdge() {
    vector<pair<int, int>> res;
    for (int i = 0 ; i < n ; i++) {
        for (auto it = begin(head[i]) ; it != end(head[i]) ; it++) {
            if (it -> idx < i) continue;
            res.emplace_back(points[i].second, points[it -> idx].second);
        }
    }
    return res;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 0 ; i < n ; i++) {
        int x, y;
        cin >> x >> y;
        points.emplace_back(Point(x, y), i);
    }
    sort(begin(points), end(points));
    for (int i = 0 ; i < n ; i++) {
        idx[points[i].second] = i;
    }
    Delaunay(0, n - 1);
    auto res = getEdge();
    for (auto &[x, y] : res) {
        cout << x << " " << y << "\n";
    }
    return 0;
}
习题

Problem - 99999383 - Codeforces

\(n\) 个点, 任意两点都有边, 长度为欧几里得距离.

q次查询两点之间的最短路.

代码
C++
{ 计算几何基础 }
struct Edge {
    int idx;
    list<Edge>::iterator nxt;
    Edge(int idx = 0) : idx(idx) {}
};
list<Edge> head[100005];
int n;
vector<pair<Point, int>> points;
void addEdge(int u, int v) {
    head[u].emplace_front(v);
    head[v].emplace_front(u);
    begin(head[u]) -> nxt = begin(head[v]);
    begin(head[v]) -> nxt = begin(head[u]);
}
void Delaunay(int L, int R) {
    if (R - L < 3) {
        for (int i = L ; i <= R ; i++) {
            for (int j = i + 1 ; j <= R ; j++) {
                addEdge(i, j);
            }
        }
        return;
    }
    int mid = L + R >> 1;
    Delaunay(L, mid);
    Delaunay(mid + 1, R);
    int _L = L, _R = R;
    for (bool up = true ; up ; ) {
        up = false;
        Point pL = points[_L].first, pR = points[_R].first;
        for (auto it = begin(head[_L]) ; it != end(head[_L]) ; it++) {
            Point t = points[it -> idx].first;
            int res = sgn(cross(pR, pL, t));
            if (res > 0 || (res == 0 && sgn(distance(pR, t) - distance(pR, pL)) < 0)) {
                _L = it -> idx;
                up = true;
                break;
            }
        }
        if (up) continue;
        for (auto it = begin(head[_R]) ; it != end(head[_R]) ; it++) {
            Point t = points[it -> idx].first;
            int res = sgn(cross(pL, pR, t));
            if (res < 0 || (res == 0 && sgn(distance(pL, t) - distance(pL, pR)) < 0)) {
                _R = it -> idx;
                up = true;
                break;
            }
        }
    }
    addEdge(_L, _R);
    while (true) {
        Point pL = points[_L].first, pR = points[_R].first;
        int ch = -1, side = 0;
        for (auto it = begin(head[_L]) ; it != end(head[_L]) ; it++) {
            if (sgn(cross(pL, pR, points[it -> idx].first)) > 0 && (ch == -1 || inCircle(points[it -> idx].first, pL, pR, points[ch].first) < 0)) {
                ch = it -> idx;
                side = -1;
            }
        }
        for (auto it = begin(head[_R]) ; it != end(head[_R]) ; it++) {
            if (sgn(cross(pR, points[it -> idx].first, pL)) > 0 && (ch == -1 || inCircle(points[it -> idx].first, pL, pR, points[ch].first) < 0)) {
                ch = it -> idx;
                side = 1;
            }
        }
        if (ch == -1) break;
        if (side == -1) {
            for (auto it = begin(head[_L]) ; it != end(head[_L]) ; ) {
                if (segmentCrossRelation(Line(pL, points[it -> idx].first), Line(pR, points[ch].first)) == 2) {
                    head[it -> idx].erase(it -> nxt);
                    head[_L].erase(it++);
                } else {
                    it++;
                }
            }
            _L = ch;
            addEdge(_L, _R);
        } else {
            for (auto it = begin(head[_R]) ; it != end(head[_R]) ; ) {
                if (segmentCrossRelation(Line(pR, points[it -> idx].first), Line(pL, points[ch].first)) == 2) {
                    head[it -> idx].erase(it -> nxt);
                    head[_R].erase(it++);
                } else {
                    it++;
                }
            }
            _R = ch;
            addEdge(_L, _R);
        }
    }
}
struct Node {
    int u, v;
    Tdouble d;
    Node() = default;
    Node(int u, int v, Tdouble d) : u(u), v(v), d(d) {}
    bool operator<(const Node &x) const {
        return sgn(d - x.d) < 0;
    }
};
vector<Node> getEdge() {
    vector<Node> res;
    for (int i = 0 ; i < n ; i++) {
        for (auto it = begin(head[i]) ; it != end(head[i]) ; it++) {
            if (it -> idx < i) continue;
            res.emplace_back(points[i].second, points[it -> idx].second, distance(points[i].first, points[it -> idx].first));
        }
    }
    return res;
}
int f[100005];
int find(int x) {
    return f[x] == x ? x : f[x] = find(f[x]);
}
vector<pair<int, double>> adj[100005];
int fa[100005][21], deep[100005];
Tdouble val[100005][21];
void dfs(int u, int p) {
    fa[u][0] = p;
    deep[u] = deep[p] + 1;
    for (int i = 1 ; (1 << i) <= deep[u] ; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
        val[u][i] = max(val[u][i - 1], val[fa[u][i - 1]][i - 1]);
    }
    for (auto &[v, d] : adj[u]) {
        if (v == p) continue;
        val[v][0] = d;
        dfs(v, u);
    }
}
int LCA(int x, int y) {
    if (deep[x] > deep[y]) swap(x, y);
    for (int i = 20 ; i >= 0 ; i--) {
        if (deep[x] > deep[fa[y][i]]) continue;
        y = fa[y][i];
    }
    if (x == y) return x;
    for (int i = 20 ; i >= 0 ; i--) {
        if (fa[x][i] == fa[y][i]) continue;
        x = fa[x][i];
        y = fa[y][i];
    }
    return fa[x][0];
}
Tdouble calc(int x, int y) {
    Tdouble res = 0;
    while (x != y) {
        for (int i = 20 ; i >= 0 ; i--) {
            if (fa[x][i] == 0 || deep[fa[x][i]] < deep[y]) continue;
            res = max(res, val[x][i]);
            x = fa[x][i];
        }
    }
    return res;
}
Tdouble solve(int u, int v) {
    int k = LCA(u, v);
    return max(calc(u, k), calc(v, k));
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 0 ; i < n ; i++) {
        int x, y;
        cin >> x >> y;
        points.emplace_back(Point(x, y), i);
    }
    sort(begin(points), end(points));
    Delaunay(0, n - 1);
    auto res = getEdge();
    sort(begin(res), end(res));
    int len = res.size();
    iota(f, f + n + 1, 0);
    for (int i = 0 ; i < len ; i++) {
        auto [u, v, d] = res[i];
        u++;
        v++;
        int x = find(u), y = find(v);
        if (x == y) continue;
        f[x] = y;
        adj[u].emplace_back(v, d);
        adj[v].emplace_back(u, d);
    }
    dfs(1, 0);
    int q;
    cin >> q;
    while (q--) {
        int x, y;
        cin >> x >> y;
        cout << fixed << setprecision(10) << solve(x, y) << "\n";
    }
    return 0;
}