树的重心--cf686d Kay and snowflake

来源:互联网 发布:零复网络是诈骗吗 编辑:程序博客网 时间:2024/06/05 16:51

1为根结点,给点其他点的根结点,求以x点为根结点的子树的重心。

树的重心:(删去该结点后,剩下树的sz都小于原来的一半)

1.若所有子结点的sz都小于树sz的一半,那么重心为根

2.若有结点的sz大于树sz的一半,那么重心在以该结点的子树中。重心在该结点到子树重心的路径上。



#include <iostream>

#include <cstdio>

#include <vector>

using namespacestd;

const int maxn =300000 + 5;

int f[maxn],son_sz[maxn],ans[maxn];

vector<int> mp[maxn];


void dfs(int x,int fa)//x的根为fa

{

    int m =0,pos = x;//在以x为根的子树中,记录最大儿子的结点数

    son_sz[x] =1;

    ans[x] = x;

    for (int i =0; i < mp[x].size(); i ++) {

        int y =mp[x][i];

        if (y != fa) {

            dfs(y, x);

            son_sz[x] +=son_sz[y];//通过dfs记录子树sz

            if (son_sz[y] > m) {

                m = son_sz[y];

                pos = y;

            }

        }

    }

    ans[x] =ans[pos];//先记录为最大子树的重心

    while (ans[x] != x &&son_sz[x] > 2 *son_sz[ans[x]]) {//若以最大子树的重心为根的树的sz,不到原树sz的一半,向上递归即可

        ans[x] =f[ans[x]];

    }

}

int main()

{

    int n,q;

    cin >> n >> q;

    f[1] =1;

    for (int i =2; i <= n ; i ++) {

        scanf("%d",&f[i]);

        mp[i].push_back(f[i]);

        mp[f[i]].push_back(i);

    }

    dfs(1,-1);

    int t;

    for(int i =0;i < q;i ++)

    {

        scanf("%d",&t);

        printf("%d\n",ans[t]);

    }

    return0;

}


阅读全文
0 0
原创粉丝点击