题意让你求每个子树的重心
直接求肯定不行对吧......然后又是在树上
考虑树的重心的性质
1.任意一个子树小于当前树的二分之一 (换句话 一棵树的重心一定是自己或者是重儿子子树上)
2.当两个子树连接的时候新接成的树的重心一定在 两个子树重心的路径上
然后发现.....这个题 可以直接分治 跑 然后就没了
嘛....主要我不会写....(就是那种似懂非懂.....原理知道,但不会操作的感觉....)
关键就在于合并.,,,
只要递归搞到子树的重心....然后逐步往上跳 直至满足与当前树合并为重心.....
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define MAXN 300005 using namespace std; int n,q,tot; int h[MAXN],ans[MAXN],f[MAXN],sz[MAXN];//以u为根的子树的重心 各点父亲 子树大小 struct node{ int from,to,next; }e[MAXN<<1]; void init(){ memset(h,-1,sizeof(h)); memset(sz,0,sizeof(sz)); } void add(int x,int y){ tot++; e[tot].from=x; e[tot].to=y; e[tot].next=h[x]; h[x]=tot; } int dfs(int now,int fa){ f[now]=fa; sz[now]=1; ans[now]=now; for(int i=h[now];i!=(-1);i=e[i].next){ if(e[i].to!=fa){ dfs(e[i].to,now); sz[now]+=sz[e[i].to]; } } for(int i=h[now];i!=(-1);i=e[i].next){ if(e[i].to!=fa&&sz[e[i].to]*2>sz[now]){ ans[now]=ans[e[i].to]; } } while((sz[now]-sz[ans[now]])*2>sz[now]){ ans[now]=f[ans[now]]; } } int main(){ cin>>n>>q;init(); for(int i=2;i<=n;i++){ int p;cin>>p; add(i,p); add(p,i); } dfs(1,1); for(int i=1;i<=q;i++){ int p;cin>>p; cout<<ans[p]<<endl; } }