AIM Tech Round 3 (Div. 1) C. Centroids(每个点能否删掉一条边再添加一条边使得这个点成为重心)

来源:互联网 发布:注册中文域名有价值吗 编辑:程序博客网 时间:2024/05/29 02:37

题意:
给你n个点的树(n<=4e5),对于每个点能否删掉一条边再添加一条边使得这个点成为重心(每一个子树的大小都小于等于n/2)


思路:
对于每个点u,判断有多少个子树的大小大于n/2
每个子树维护这个子树中节点数小于等于n/2的最大值,次大值以及它们对应的节点

向上和向下dp一下就可以了


#include<bits/stdc++.h>using namespace std;const int INF=0x3f3f3f3f;const int N=4e5+100;struct Edge{    int to,next;}e[N*2];int tot,head[N],n,size[N],mx,a[N],up[N],up_max[N];void init(){    tot=0;    memset(head,-1,sizeof(head));}void addedge(int from,int to){    e[tot]=(Edge){to,head[from]};    head[from]=tot++;}struct node1{    int maxv1,id1,maxv2,id2;}b[N];void getmx(int u,int num,int v){    if(b[u].maxv1<num){        b[u].maxv2=b[u].maxv1,b[u].id2=b[u].id1;        b[u].maxv1=num,b[u].id1=v;    }    else if(b[u].maxv2<num)        b[u].maxv2=num,b[u].id2=v;}void dfs1(int u,int pre){    size[u]=1,a[u]=1;    for(int i=head[u];i!=-1;i=e[i].next){        int v=e[i].to;        if(v==pre)  continue;        dfs1(v,u);        a[u]=max(a[u],size[v]);        if(size[v]<=mx)  getmx(u,size[v],v);        else    getmx(u,b[v].maxv1,v);        size[u]+=size[v];    }    up[u]=n-size[u];}void dfs2(int u,int pre){    for(int i=head[u];i!=-1;i=e[i].next){        int v=e[i].to;        if(v==pre)  continue;        if(b[u].id1!=v)  up_max[v]=max(b[u].maxv1,up_max[v]);        else    up_max[v]=max(b[u].maxv2,up_max[v]);        if(n-size[v]<=mx)   up_max[v]=max(up_max[v],n-size[v]);        up_max[v]=max(up_max[v],up_max[u]);        dfs2(v,u);    }}int main(){    int u,v;    scanf("%d",&n);    mx=n/2,init();    for(int i=1;i<n;i++){        scanf("%d%d",&u,&v);        addedge(u,v);        addedge(v,u);    }    dfs1(1,0);    dfs2(1,0);    for(int i=1;i<=n;i++){        if(a[i]<=mx&&up[i]<=mx)            printf("1 ");        else if(a[i]>mx&&a[i]-b[i].maxv1<=mx)            printf("1 ");        else if(up[i]>mx&&up[i]-up_max[i]<=mx)            printf("1 ");        else            printf("0 ");    }    return 0;}
0 0
原创粉丝点击