2019icpc徐州站 M 【Kill the tree】(找各点重心)

题目链接https://nanti.jisuanke.com/t/42552

题意:一开始建1个以1为root的树,然后找以各个节点作为根其子树中的重心是谁

解法:推荐博客:https://www.cnblogs.com/ctyakwf/p/12010370.html

   这个题是一个非常不错的重心性质问题。我们以son代表以x为根的重儿子。倘若siz[son]*2>=siz[x],那么这个重心势必在son的重心和x之间,否则就是x。所以呢我们需要在res[son]至x中间爬,爬到所谓真正的x的重心(我们一开始都初始化x的重心为他自己),一旦siz[x]-2*siz[res[son]]>0,那么代表这个x的真正重心还能往上爬。爬到<=为止。最后你需要特判一下if(siz[x]==2*siz[res[x]])。这种等于情况显然就是会出现2个重心的情况,会出现两个解。

AC代码:

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int fa[maxn],n;int siz[maxn],res[maxn],res1[maxn];
void dfs(int x,int f){
    siz[x]=1;res[x]=x;
    int son=0;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v==f) continue;
        fa[v]=x;
        dfs(v,x);
        siz[x]+=siz[v];
        if(siz[v]>siz[son]) son=v;
    }
    if(siz[son]*2>=siz[x]){
        res[x]=res[son];
        while(siz[x]-2*siz[res[x]]>0){
            res[x]=fa[res[x]];
        }
        if(siz[x]==2*siz[res[x]]){
            res1[x]=fa[res[x]];
        }
    }
}
int main(){
    scanf("%d",&n);mem(head,-1);
    rep(i,1,n-1){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    fa[1]=1;
    dfs(1,-1);
    rep(i,1,n){
        if(res1[i]) printf("%d ",min(res1[i],res[i]));
        printf("%d\n",max(res1[i],res[i]));
    }
}
View Code

 

posted @ 2020-07-20 15:39  Anonytt  阅读(191)  评论(0编辑  收藏  举报