树的重心--cf686d Kay and snowflake

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

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

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

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



#include <iostream>

#include <cstdio>

#include <vector>

using namespace std;

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]);

    }

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值