codeforces 685 B (求所有子树重心)

sz[x]代表以x为根的子树大小,hs[x]代表以x为根的重儿子,kp[x]代表以x为根的重心。树的重心有如下结论:x的重心在其重儿子的重心到x的这条链上,即kp[hs[x]]到x的这条链上。所以从kp[hs[x]]向上枚举至x。如果枚举到节点g满足:sz[hs[g]] * 2 <= sz[x] && (sz[x] - sz[g]) * 2 <= sz[x]则该点即为以x为根的子树的重心。

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
#define maxn 300010
#define ios cin.tie(0) ,cout.tie(0), cout.sync_with_stdio(0)
typedef long long ll;
struct edge{
    int v,nxt;
}e[maxn];
int head[maxn],en;
int hs[maxn],sz[maxn],kp[maxn];
int fa[maxn];
void init(){
    en=0;memset(head,-1,sizeof(head));
}
void adde(int u,int v){
    e[++en].v=v;e[en].nxt=head[u];head[u]=en;
}
void dfs(int x){
    //printf("x=%d\n",x);
    sz[x]=1;kp[x]=x;int sw=0;
    for(int i=head[x];i!=-1;i=e[i].nxt){
        int v=e[i].v;
        dfs(v);sz[x]+=sz[v];
        if(sw<sz[v])hs[x]=v,sw=sz[v];
    }
    int p=kp[hs[x]];
    while(p&&p!=fa[x]){
        //printf("p=%d\n",p);
        if(sz[hs[p]]*2<=sz[x]&&(sz[x]-sz[p])*2<=sz[x]){
            kp[x]=p;break;
        }
        p=fa[p];
    }
}
int main(){
    init();
    int n,q;scanf("%d%d",&n,&q);
    for(int i=2;i<=n;i++){
        scanf("%d",&fa[i]);adde(fa[i],i);
    } 
    dfs(1);
    while(q--){
        int x;scanf("%d",&x);printf("%d\n",kp[x]);
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/cleanerhgf/p/11986537.html