题目链接:
http://codeforces.com/problemset/problem/685/B
题意:
给你n个点,以1为根,然后给你2-n的节点的父亲节点编号。问你每一颗子树的重心是哪一个节点。
思路:
有定理:把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。
考虑树的重心在哪个部分,一定是在当前节点u的最大子树v中,假设我们已经知道了子树v的重心ans[v],那么u的重心呢?就是在ans[v]这个节点到u的路径上。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } // const int maxn = 3e5+10; int n,q,fa[maxn],son[maxn],ans[maxn]; vector<int> g[maxn]; void dfs(int u){ son[u] = 1; ans[u] = u; int mx = 0; for(int i=0; i<(int)g[u].size(); i++){ int v = g[u][i]; dfs(v); son[u] += son[v]; if(son[v] > son[mx]) mx = v; } if(mx==0) return ; int now = ans[mx]; while(son[now]*2<son[u]) now = fa[now]; ans[u] = now; } int main(){ cin >> n >> q; for(int i=2; i<=n; i++){ cin >> fa[i]; g[fa[i]].push_back(i); } dfs(1); for(int i=0; i<q; i++){ int x = read(); cout << ans[x] << endl; } return 0; }