MST

模板。

#include <bits/stdc++.h>

using namespace std;


#define N 100010
#define M 1000010
#define ULL unsigned long long
#define LL long long
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define inf 0x3f3f3f3f
#define eps 1e-6
#define pii pair<int, int>
#define MP make_pair
#define mod 1000000007
#define sqr(x) ((x) * (x))

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}
struct point {
    double x, y;
    int id;
    struct Edge *e;
    bool operator < (const point & p) const {
        return dcmp(x - p.x) != 0 ? x < p.x : dcmp(y - p.y) < 0;
    }
    bool operator == (const point & p) const {
            return dcmp(x - p.x) == 0 && dcmp(y - p.y) == 0;
    }
    void input(int i) {
        id = i;
        scanf("%lf%lf", &x, &y);
    }
}p[N];
double cross(point & o, point & a, point & b) {
    return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}
double dot(point & o, point & a, point & b) {
    return (a.x - o.x) * (b.x - o.x) + (a.y - o.y) * (b.y - o.y);
}
double dis(point a, point b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct Edge {
    point *o, *d;
    Edge *on, *op, *dn, *dp;
};
#define Op(e,p) ((e)->o==p?(e)->d:(e)->o)
#define Next(e,p) ((e)->o==p?(e)->on:(e)->dn)
#define Prev(e,p) ((e)->o==p?(e)->op:(e)->dp)
struct Delaunay {
    void solve(point * ps, int n) { //点集需要 sort 和 unique
        sort(ps, ps + n);
        edge_num = 0;
        rubb = NULL;
        for (int i = 0; i < n; i++) ps[i].e = NULL;
        Edge* l_cw, *r_ccw;
        divide(ps, 0, n, l_cw, r_ccw);
    }
    Edge es[M], *rubb;
    int edge_num;
    Edge *make_edge(point &u, point &v) {
        Edge * e;
        if (rubb == NULL) {
            e = es + edge_num++;
        }
        else {
            e = rubb;
            rubb = rubb->dn;
        }
        e->on = e->op = e->dn = e->dp = e;
        e->o = &u; e->d = &v;
        if (u.e == NULL) u.e = e;
        if (v.e == NULL) v.e = e;
        return e;
    }
    void delete_edge(Edge *e) {
        point *u = e->o, *v = e->d;
        if (u->e == e) u->e = e->on;
        if (v->e == e) v->e = e->dn;
        Prev(e->on, u) = e->op;
        Next(e->op, u) = e->on;
        Prev(e->dn, v) = e->dp;
        Next(e->dp, v) = e->dn;
        e->dn = rubb;
        rubb = e;
    }
    void splice(Edge *a, Edge *b, point *v) {
        Edge *n;
        n = Next(a, v); Next(a, v) = b;
        Prev(n, v) = b;
        Next(b, v) = n; Prev(b, v) = a;
    }
    Edge *join(Edge *a, point *u, Edge *b, point *v, int s) {
        Edge *e = make_edge(*u, *v);
        if (s == 0) {
            splice(Prev(a, u), e, u);
            splice(b, e, v);
        }
        else {
            splice(a, e, u);
            splice(Prev(b, v), e, v);
        }
        return e;
    }
    void lower_tangent(Edge * & l, Edge * & r, point * & s, point * & u) {
        point *dl = Op(l, s), *dr = Op(r, u);
        while (1) {
            if (dcmp(cross((*s), (*dl), (*u))) > 0) {
                    l = Prev(l, dl); s = dl; dl = Op(l, s);
            }
            else if (dcmp(cross((*u), (*dr), (*s))) < 0) {
                r = Next(r, dr); u = dr; dr = Op(r, u);
            }
            else break;
        }
    }
    void merge(Edge *r_cw_l, point *s, Edge *l_ccw_r, point *u, Edge
        **l_tangent) {
        Edge *b, *lc, *rc;
        point *dlc, *drc;
        double crc, clc;
        lower_tangent(r_cw_l, l_ccw_r, s, u);
        b = join(r_cw_l, s, l_ccw_r, u, 1);
        *l_tangent = b;
        do {
            lc = Next(b, s); rc = Prev(b, u); dlc = Op(lc, s); drc = Op(rc, u);
            double cplc = cross(*dlc, *s, *u);
            double cprc = cross(*drc, *s, *u);
            bool alc = dcmp(cplc)>0, arc = dcmp(cprc)>0;
            if (!alc && !arc) break;
            if (alc) {
                clc = dot(*dlc, *s, *u) / cplc;
                do {
                    Edge * next = Next(lc, s);
                    point & dest = *Op(next, s);
                    double cpn = cross(dest, *s, *u);
                    if (dcmp(cpn) <= 0) break;
                    double cn = dot(dest, *s, *u) / cpn;
                    if (dcmp(cn - clc)>0) break;
                    delete_edge(lc);
                    lc = next;
                    clc = cn;
                } while (1);
            }
            if (arc) {
                crc = (double)dot(*drc, *s, *u) / cprc;
                do {
                    Edge * prev = Prev(rc, u);
                    point & dest = *Op(prev, u);
                    double cpp = cross(dest, *s, *u);
                    if (dcmp(cpp) <= 0) break;
                    double cp = dot(dest, *s, *u) / cpp;
                    if (dcmp(cp - crc) > 0) break;
                    delete_edge(rc);
                    rc = prev;
                    crc = cp;
                } while (1);
            }
            dlc = Op(lc, s); drc = Op(rc, u);
            if (!alc || (alc && arc && dcmp(crc - clc) < 0)) {
                b = join(b, s, rc, drc, 1);
                u = drc;
            }
            else {
                b = join(lc, dlc, b, u, 1);
                s = dlc;
            }
        } while (1);
    }
    void divide(point *p, int l, int r, Edge * & l_ccw, Edge * & r_cw) {
        int n = r - l;
        Edge *l_ccw_l, *r_cw_l, *l_ccw_r, *r_cw_r, *l_tangent, *c;
        if (n == 2) {
            l_ccw = r_cw = make_edge(p[l], p[l + 1]);
        }
        else if (n == 3) {
            Edge * a = make_edge(p[l], p[l + 1]), *b = make_edge(p[l + 1], p[l + 2]);
            splice(a, b, &p[l + 1]);
            double c_p = cross(p[l], p[l + 1], p[l + 2]);
            if (dcmp(c_p)>0) {
                c = join(a, &p[l], b, &p[l + 2], 1); l_ccw = a; r_cw = b;
            }
            else if (dcmp(c_p) < 0) {
                c = join(a, &p[l], b, &p[l + 2], 0); l_ccw = c; r_cw = c;
            }
            else {
                l_ccw = a; r_cw = b;
            }
        }
        else if (n > 3) {
            int split = (l + r) / 2;
            divide(p, l, split, l_ccw_l, r_cw_l);
            divide(p, split, r, l_ccw_r, r_cw_r);
            merge(r_cw_l, &p[split - 1], l_ccw_r, &p[split], &l_tangent);
            if (l_tangent->o == &p[l]) l_ccw_l = l_tangent;
            if (l_tangent->d == &p[r - 1]) r_cw_r = l_tangent;
            l_ccw = l_ccw_l; r_cw = r_cw_r;
        }
    }
} de;
struct tree_edge {
    int u, v;
    double c;
    tree_edge(int u = 0, int v = 0, double c = 0) : u(u), v(v), c(c) {}
    bool operator < (const tree_edge &b) const {
        return c < b.c;
    }
}tree_e[M];

void addEdge(int &k, int u, int v, double d) {
    tree_e[++k] = tree_edge(u, v, d);
}
void getEdge(int &k, int n) {
    k = 0;
    Edge *st, *cur;
    point *u, *v;
    for (int i = 0; i < n; ++i) {
        u = &pnt[i];
        st = cur = u->e;
        do {
            v = Op(cur, u);
            if (u < v)
                addEdge(k, u->id, v->id, dis(*u, *v));
        } while ((cur = Next(cur, u)) != st);
    }

}
void enum_triangle(point *ps, int n) {
    Edge *e_start, *e, *nxt;
    point *u, *v, *w;
    for (int i = 0; i < n; i++) {
        u = &ps[i];
        e_start = e = u->e;
        do {
            v = Op(e, u);
            if (u < v) {
                nxt = Next(e, u);
                w = Op(nxt, u);
                if (u < w && Next(nxt, w) == Prev(e, v)) {
                    // now, (u v w) is a triangle!!!!!!
                    // 这时,uvw 的外接圆是空的(不包含 ps 中的其他点),如果要求最大空圆,则计算 uvw 的外接圆就可以!
                }
            }
        } while ((e = Next(e, u)) != e_start);
    }
}

int n, fa[N];
struct LCA{
    int fst[N], vv[M], nxt[M], dep[N], e;
    double cost[M], fee[N][22];
    int fa[N][22];
    void init(){
        memset(fst, -1, sizeof fst); e = 0;
    }
    void add(int u, int v, double c){
        vv[e] = v, nxt[e] = fst[u], cost[e] = c, fst[u] = e++;
    }
    void dfs(int u, int p, int d, double c){
        fa[u][0] = p, dep[u] = d, fee[u][0] = c;
        for(int i = fst[u]; ~i; i = nxt[i]){
            int v = vv[i];
            if(v == p) continue;
            dfs(v, u, d + 1, cost[i]);
        }
    }
    void init_lca(){
        for(int k = 0; k < 21; ++k)
            for(int i = 1; i <= n; ++i){
                if(fa[i][k] == -1)
                    fa[i][k+1] = -1, fee[i][k+1] = fa[i][k];
                else
                    fa[i][k+1] = fa[fa[i][k]][k],
                    fee[i][k+1] = max(fee[i][k], fee[fa[i][k]][k]);
            }
    }
    double lca(int u, int v){
        double ret = 0;
        if(dep[u] > dep[v]) swap(u, v);
        for(int i = 0; i < 21; ++i)
            if((dep[v] - dep[u]) >> i & 1){
                ret = max(ret, fee[v][i]);
                v = fa[v][i];
            }
        if(v == u) return ret;
        for(int i = 21; i >= 0; --i)
            if(fa[u][i] != fa[v][i]){
                ret = max(ret, fee[u][i]);
                ret = max(ret, fee[v][i]);
                u = fa[u][i], v = fa[v][i];
            }
        ret = max(ret, fee[u][0]);
        ret = max(ret, fee[v][0]);
        return ret;
    }
}go;

int find(int u){
    if(fa[u] != u) fa[u] = find(fa[u]);
    return fa[u];
}
int main() {
    do{
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            scanf("%lf%lf", &pnt[i].x, &pnt[i].y);
            pnt[i].id = i + 1;
        }
        de.solve(pnt, n);
        int k = 0;
        getEdge(k, n);
        sort(tree_e + 1, tree_e + 1 + k);

        for(int i = 0; i <= n; ++i) fa[i] = i;
        double ans = 0;
        go.init();
        for (int i = 1; i <= k; ++i){
            int u = tree_e[i].u, v = tree_e[i].v;
            double c = tree_e[i].c;
            int fu = find(u), fv = find(v);
            if(fu == fv) continue;
            fa[fu] = fv;
            go.add(u, v, c);
            go.add(v, u, c);
            ans += c;
        }
        go.dfs(1, -1, 0, 0);
        go.init_lca();
        int m;
        scanf("%d", &m);
        while(m--){
            int u, v;
            scanf("%d%d", &u, &v);
            printf("%.6f\n", go.lca(u, v));
        }


    }while(0);
    return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值