首页 > 代码库 > Codeforces 686 D.Kay and Snowflake (dfs 树的重心)

Codeforces 686 D.Kay and Snowflake (dfs 树的重心)

题目链接:

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

 

Codeforces 686 D.Kay and Snowflake (dfs 树的重心)