Codeforces Round #359 (Div. 2) D

D - Kay and Snowflake

题目大意:给你一棵数q个询问,每个询问给你一个顶点编号,要你求以这个点为根的子树的重心是哪个节点。

定义:一棵树的顶点数为n,将重心去掉了以后所有子树的顶点的个数的两倍不会超过n。

性质 1 :树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。

性质 2 :把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上。

性质 3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

 1 #include<bits/stdc++.h>
 2 #define fi first
 3 #define se second
 4 #define mk make_pair
 5 #define ll long long
 6 #define pll pair<ll,ll>
 7 #define pii pair<int,int>
 8 #define read(x) scanf("%d",&x)
 9 #define sread(x) scanf("%s",x)
10 #define dread(x) scanf("%lf",&x)
11 #define lread(x) scanf("%lld",&x)
12 using namespace std;
13 
14 
15 const int N=1e6+7;
16 const int M=1e7+7;
17 const int inf=0x3f3f3f3f;
18 const ll INF=0x3f3f3f3f3f3f3f3f;
19 const int mod=1e9+7;
20 
21 int n,q,sum[N],fa[N],ans[N];
22 vector<int> edge[N];
23 
24 int dfs(int u)
25 {
26     sum[u]=1; ans[u]=u;
27     for(int v:edge[u])
28         sum[u]+=dfs(v);
29 
30     for(int v:edge[u])
31         if(sum[v]*2>sum[u])
32             ans[u]=ans[v];
33 
34     while((sum[u]-sum[ans[u]])*2>sum[u])
35         ans[u]=fa[ans[u]];
36 
37     return sum[u];
38 }
39 
40 int main()
41 {
42     read(n); read(q);
43     for(int i=2;i<=n;i++)
44     {
45         int pre; read(pre);
46         edge[pre].push_back(i);
47         fa[i]=pre;
48     }
49     dfs(1);
50     while(q--)
51     {
52         int u; read(u);
53         printf("%d
",ans[u]);
54     }
55     return 0;
56 }
57 /*
58 
59 */
原文地址:https://www.cnblogs.com/CJLHY/p/8575603.html