Codeforces Round #359 (Div. 2) D. Kay and Snowflake

本文详细介绍了树的重心概念及其重要性质,包括如何找到树的重心,并提供了完整的C++实现代码。文中阐述了树的重心定义及三个核心性质,解释了在树结构中寻找重心的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重心的定义是:以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

1.树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。

2.把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。

3.把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

一棵树的重心是它的子树的重心和这棵树的祖宗节点连的几条线中的其中一点(2)

每推一个点所支配的子树时 它的重心是它分支的重心往上遍历当首次出现这个点支配的点的数量减去分支重心支配的点的数量小于等于这个点支配数量的二分之一时,这时往上遍历的这个点就是这棵子树的重心,此时的重心的所支配的(所有子节点的数量)保证也小于等于这棵子树点的数量的二分之一

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#define maxn 300005
using namespace std;
int n,m;
int link[maxn],fa[maxn],ans[maxn];
vector<int>ve[maxn];
void dfs(int pre)
{
    link[pre] = 1;
    for(int i=0;i<ve[pre].size();i++)
    {
        dfs(ve[pre][i]);
        link[pre]+=link[ve[pre][i]];
    }
    int ans2 = pre;
    bool sym = false;
    for(int i=0;i<ve[pre].size();i++)
    {
        int pre2 = ans[ve[pre][i]];
        while((link[pre]-link[pre2])*2>=link[pre])pre2 = fa[pre2];
        if(pre2!=pre)
        {
            ans2 = pre2;
            break;
        }
    }
    ans[pre] = ans2;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=2;i<=n;i++)
    {
        int pre;
        scanf("%d",&pre);
        fa[i] = pre;
        ve[pre].push_back(i);
    }
    dfs(1);
    while(m--)
    {
        int pre;
        scanf("%d",&pre);
        printf("%d\n",ans[pre]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值