D. Kay and Snowflake
题目链接:http://codeforces.com/contest/686/problem/D
题意:
给你n个点,以1为根,问你每一颗子树的重心是哪一个节点。
解题思路:
很明显的树形DP,每棵树的重心一定在每个子树的重心到该点的路径上,但是如果考虑这些路径所有的点可能会超时,这是我们可以想到:如果该树的子树的结点数大于该树的两倍那么就不用往上找了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=300005;
const int inf=0x3f3f3f3f;
struct st{
int to,next;
}stm[maxn*2];
int head[maxn];
int cnt;
void add(int u,int v){
stm[cnt].to=v;
stm[cnt].next=head[u];
head[u]=cnt++;
}
int ans[maxn];
int dp[maxn];//最大子树大小
int dp1[maxn];//当前树大小
int pre[maxn];
void dfs(int now,int fa){
dp1[now]=1;
dp[now]=0;
ans[now]=now;
for(int i=head[now];~i;i=stm[i].next){
int to=stm[i].to;
if(to==fa)continue;
pre[to]=now;
dfs(to,now);
dp1[now]+=dp1[to];
if(dp[now]<=dp1[to]){
dp[now]=dp1[to];
}
}
int tem=dp1[now];
for(int i=head[now];~i;i=stm[i].next){
int pos=stm[i].to;
if(pos==fa)continue;
int tem1=ans[pos];
while(dp1[tem1]*2<=dp1[now]){
if(tem>=max(dp[tem1],dp1[now]-dp1[tem1])){
ans[now]=tem1;
tem=max(dp[tem1],dp1[now]-dp1[tem1]);
}
tem1=pre[tem1];
}
if(tem>=max(dp[tem1],dp1[now]-dp1[tem1])){
ans[now]=tem1;
tem=max(dp[tem1],dp1[now]-dp1[tem1]);
}
}
}
int main(){
int n,q;
int tem;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&q);
pre[1]=1;
for(int i=2;i<=n;i++){
pre[i]=i;
scanf("%d",&tem);
add(i,tem);
add(tem,i);
}
dfs(1,0);
//for(int i=1;i<=n;i++)cout<<dp1[i]<<endl;
for(int i=1;i<=q;i++){
scanf("%d",&tem);
printf("%d\n",ans[tem]);
}
return 0;
}

浙公网安备 33010602011771号