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; }