EOJ-A 昔我往矣(倍增LCA+乱搞)

 

 

题解:

既然只有5个点,那就无限乱搞,我的做法是不断取出当前点集两两之间的LCA插入点集,直到所有两两之间的LCA都已经在点集中了。

这一步的时间复杂度我感觉是一个调和级数,是可以被忽略的。

然后对每个点保存它的最深父亲,然后对点集建一棵树,对这棵树算边权贡献即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
int n,q;
struct node {
    int u,v,w,nxt;
}edge[maxn<<1];
int head[maxn],tot;
void addedge (int u,int v,int w) {
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].nxt=head[u];
    head[u]=tot++;
    
    edge[tot].u=v;
    edge[tot].v=u;
    edge[tot].w=w;
    edge[tot].nxt=head[v];
    head[v]=tot++;
} 

int father[30][maxn];
int h[maxn],d[maxn];
void dfs (int x) {
    for (int i=head[x];i!=-1;i=edge[i].nxt) {
        int v=edge[i].v;
        if (v==father[0][x]) continue;
        father[0][v]=x;
        h[v]=h[x]+1;
        d[v]=d[x]+edge[i].w;
        //printf("%d %d\n",v,h[v]);
        dfs(v);
    }
}
int lca (int x,int y) {
    if (h[x]<h[y]) swap(x,y);
    for (int i=20;i>=0;i--)
        if (h[x]-h[y]>>i) x=father[i][x];
    if (x==y) return x;
    for (int i=20;i>=0;i--) 
        if (father[i][x]!=father[i][y]) {
            x=father[i][x];
            y=father[i][y];
        }
    return father[0][x];
}
int getDis (int x,int y) {
    return d[x]+d[y]-d[lca(x,y)]*2;
}
int getH (int x,int y) {
    return h[x]+h[y]-h[lca(x,y)]*2;
}
int x[maxn],ans,f[maxn];
vector<int> g[maxn];
void dfs1 (int x,int f) {
    for (int y:g[x]) {
        if (y==f) continue;
        ans+=getDis(x,y);
        dfs1(y,x);
    }
}
int main () {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) head[i]=-1;
    for (int i=1;i<n;i++) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        u++,v++;
        addedge(u,v,w);
    }
    h[1]=1;
    dfs(1);
    for (int i=1;i<=20;i++) for (int j=1;j<=n;j++) father[i][j]=father[i-1][father[i-1][j]];
    scanf("%d",&q);
    while (q--) {
        for (int i=1;i<=5;i++) scanf("%d",x+i),x[i]++;
        int m=5;
        set<int> st;
        for (int i=1;i<=5;i++) {
            st.insert(x[i]);
        }
        while (1) {
            int f=1;
            for (int i=1;i<=m;i++) {
                for (int j=i+1;j<=m;j++) {
                    int tt=lca(x[i],x[j]);
                    if (!st.count(tt)) {
                        st.insert(tt);
                        x[++m]=tt;
                        f=0;
                    }
                }
            }
            if (f) break;
        }
        for (int i=1;i<=m;i++) f[x[i]]=0,g[x[i]].clear(); 
        for (int i=1;i<=m;i++) {
            for (int j=i+1;j<=m;j++) {
                int tt=lca(x[i],x[j]);
                if (tt==x[i]) {
                    if (h[x[i]]>h[f[x[j]]]) {
                        f[x[j]]=x[i];
                    }
                }
                else if (tt==x[j]) {
                    if (h[x[j]]>h[f[x[i]]]) {
                        f[x[i]]=x[j];
                    }
                }
            }
        }
        int rt=0;
        for (int i=1;i<=m;i++) {
            //printf("%d %d\n",x[i],f[x[i]]);
            if (!f[x[i]]) {
                rt=x[i];
                continue;
            }
            g[f[x[i]]].push_back(x[i]);
        }
        ans=0;
        dfs1(rt,0);
        printf("%d\n",ans);
    }
}

 

posted @ 2021-02-06 18:36  zlc0405  阅读(109)  评论(0编辑  收藏  举报