重心-[Codeforces709E] Centroids

来源:互联网 发布:关于网络舆论的法律 编辑:程序博客网 时间:2024/06/07 05:12

题目就是给出一颗树,对于每一个点,如果改变树的一条边(可以不变),是否能让这个点变成重心;
zzh学长教我时,告诉我这是贪心(其实好像是树形dp),因为重心的最大的子树大小不超过全树的一半,所以贪心也是方便的,即尽可能让某个点的最大的子树大小不超过全树的一半;所谓改变一条边,显然是在某点的最大的子树里砍掉一边,添加到别的地方,这样可以使整棵树相对于这个点更平衡;
但是我们要删掉哪一条边,添加到哪里,这就要贪心了;
设询问某点x
我们知道,原先的树也是有重心的,设其是y;显然,y一定在x的最大的子树里;如果我们要建立一个新的重心x,就一定要破坏原先的重心y,很显然,改变的最优方法必然是在原重心y附近截取一个子树移到x上;
显然的,割掉原先y的最大子树接到x上是比较好的,因为y的最大子树一定不超过全树的一半,且去掉y的最大子接到x上,重心一定会从y向x移;感觉就是这样,把y的最大子树移动到x上,最优;
但本蒟蒻无法证明~~~;
当然咯,如果x恰好就在y的最大子树上,那就尴尬了,要判断两种较优情况
1.取y的次大子树接到x上;
2.把割掉y的最大子树后的那颗树接到x上;
就是这样,感觉这个贪心蒙出来的,还是dp靠谱
如果原来有好多重心,任意

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>#define LL long longusing namespace std;struct cs{    int to,next;}a[800009];int head[400010],v[400005],vv[400005];//链表存,v[i]是i节点的最大子树,vv[i]是次大 bool b[400005];//标记点i是否在原重心的最大子树上 int n,m,x,y,ans,ll,maxc,z;void inc(int x,int y){    ll++;    a[ll].to=y;    a[ll].next=head[x];    head[x]=ll;}int dfs(int x,int y){    int k=head[x],an1=0,an=0,c=0,ann=0;    int sum=1;    while(k){        if(a[k].to!=y)an=dfs(a[k].to,x);else an=0;        sum+=an;        if(an>an1){            if(an1>ann)ann=an1;            an1=an;c=a[k].to;        }else if(an>ann)ann=an;        k=a[k].next;    }    an=n-sum;    if(an>an1){        if(an1>ann)ann=an1;        an1=an;c=y;    }else if(an>ann)ann=an;    v[x]=an1;vv[x]=ann;    if(an1<=n/2){        ans=x;maxc=c;    }    return sum;}int dfs2(int x,int y){    int k=head[x];    while(k){        if(a[k].to!=y){            b[a[k].to]=1;            dfs2(a[k].to,x);        }        k=a[k].next;    }}int main(){        memset(head,0,sizeof head);        ll=0;        scanf("%d",&n);        for(int i=1;i<=n-1;i++){            scanf("%d%d",&x,&y);            inc(x,y);            inc(y,x);        }    int k=head[1],an1=0,an=0,c=0,ann=0;    while(k){        an=dfs(a[k].to,1);        if(an>an1){            if(an1>ann)ann=an1;            an1=an;c=a[k].to;        }else if(an>ann)ann=an;        k=a[k].next;    }    v[1]=an1; vv[1]=ann;    if(an1<=n/2){        ans=1;maxc=c;    }    b[maxc]=1;    dfs2(maxc,ans);    for(int i=1;i<=n;i++){        if(b[i]){            if(max(v[i]-vv[ans],vv[ans])<=n/2){printf("1 ");continue;}            if(n-v[ans]<=n/2){printf("1 ");continue;}            printf("0 ");        }else{            if(max(v[ans],v[i]-v[ans])<=n/2){printf("1 ");continue;}            printf("0 ");        }    }}
1 0
原创粉丝点击