树的重心

时间:2022-07-28
本文章向大家介绍树的重心,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

定义:

1.找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。 2.以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

性质:

1.树中所有点到某一点距离之和中,到重心的距离和最短。

2.把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。 3.把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

DP的记忆化搜索来求解。

const int maxn=500005;
int tot=0,n;
int ans,size;
int sx[maxn],head[maxn];
int vis[maxn];
struct edge
{
    int to,next;
} eg[maxn];
void add(int u,int v)
{
    eg[tot].to=v;
    eg[tot].next=head[u];
    head[u]=tot++;
}
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void dfs(int u)
{
    vis[u]=1;
    sx[u]=1;
    int tmp=0;
    for(int i=head[u]; i!=-1; i=eg[i].next)
    {
        int v=eg[i].to;
        if(!vis[v])
        {
            dfs(v);
            sx[u]+=sx[v];
            tmp=max(tmp,sx[v]);
        }
    }
    tmp=max(tmp,n-sx[u]);
    if(size>tmp||size==tmp&&ans>u)
    {
        ans=u;
        size=tmp;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        int u,v;
        scanf("%d",&n);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        size=INF;
        dfs(1);
        printf("%d %dn",ans,size);
    }
}