Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) G. The Winds of Winter

题意

链接

题解

我们考虑考虑一个一个点考虑
那么显然,肯定是把最大的联通块分一点到最小的联通块里面
扫一下就可以知道最大和最小了
当然,答案要和次大的子树取max
那么问题就是分多少,怎么分
显然地,如果两个相差是x
那么分的方式x/2显然是最优的
如果不存在的话那么就去最近的两个
那么我们就需要维护这个东西了
我们需要维护三个set
这个点重儿子里面的子树大小
这个点到根的路径的子树大小
剩下的全部
对于第三个,我们可以用删除的方式,然后剩下两个都是每一次加进来
这个显然可以用dsu来优化,然后就可以了
注意的是,最大子树要是父亲的联通块时要分开考虑
CODE:(打着打着就打长了)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=100005*2;
int n;
int rt;
struct qq
{
    int x,y,last;
}e[N];int num,last[N];
void init (int x,int y)
{
    num++;
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
int tot[N];
int son[N];
multiset<int> s,s1,s2;//s:不是这个点到根以及这个点子树里面的   s1:子树里面的   s2:这个点到根里面的
multiset<int>::iterator it;
void dfs (int x,int fa)
{
    tot[x]=1;
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        dfs(y,x);
        tot[x]=tot[x]+tot[y];
        if (tot[y]>tot[son[x]]) son[x]=y;
    }
    s.insert(tot[x]);
}
int ans[N];
void del (int x,int fa)//把这个从子树里面删除 
{
    it=s1.lower_bound(tot[x]);s1.erase(it);
    s.insert(tot[x]);
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        del(y,x);
    }
}
void Ins (int x,int fa)
{
    it=s.lower_bound(tot[x]);s.erase(it);
    s1.insert(tot[x]);
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        Ins(y,x);
    }
}
void print ()
{
    printf("OZY:\n");
    for (it=s.begin();it!=s.end();it++)
    {
        printf("%d ",(*it));
    }
    printf("\n");
}
void dfs1 (int x,int fa)
{
    s2.insert(tot[x]);
    it=s.lower_bound(tot[x]);s.erase(it);
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        if (y==son[x]) continue;
        dfs1(y,x);del(y,x);
    }
    if (son[x]!=0)  dfs1(son[x],x);
    else
    {
        ans[x]=n-1;s1.insert(tot[x]);
        it=s2.lower_bound(tot[x]);s2.erase(it);
        return ;
    }
    int o=0,id,mn=tot[son[x]];
    int mx=tot[son[x]];
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        if (y==son[x]) continue;
        /*if (x==1)
        {
            printf("hehe:%d %d\n",tot[y],mn);
        }*/
        if (tot[y]>o)   o=tot[y];
        mn=min(mn,tot[y]);
    }
//if (x==1)printf("TYB:%d %d\n",x,mn);
    if (fa!=0) mn=min(mn,n-tot[x]); 
    if (mx<n-tot[x])//问题是父亲
    {
        for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==son[x]||y==fa) continue;
        Ins(y,x);
    }
    //  printf("x:%d %d\n",x,o);
        if (n-tot[x]==tot[son[x]])//如果两个一样 
        {
            ans[x]=mx;
        }
        else
        {
            o=mx;
            mx=n-tot[x];
            int r=(mx-mn)/2;//最多拿出多少个
    /*  if (x==2)   
        {
            printf("YES:%d %d %d %d\n",x,mn,mx,r);print();
        }*/
            int lalal=0;
            int g=n;
            it=s.lower_bound(r+1);
            if (it!=s.end()) g=min(g,max(mx-(*it),mn+(*it)));
            //printf("first:%d\n",(*it));
            if (it!=s.begin())
            {
                it--;
                g=min(g,max(mx-(*it),mn+(*it)));
            }

            it=s2.lower_bound(r+1+tot[x]);
            if (it!=s2.end()) g=min(g,max(mx-((*it)-tot[x]),mn+((*it)-tot[x])));
            if (it!=s2.begin())
            {
                it--;
                g=min(g,max(mx-((*it)-tot[x]),mn+((*it)-tot[x])));
            }
            //  printf("ans:%d\n",g);
            ans[x]=max(o,g);
        }
    }
    else if (o==0&&fa==0)
    {
        ans[x]=n-1;
    }
    else//只需要把重搞走就可以了 
    {
        o=max(o,n-tot[x]);
        if (o==mx)
        {
            ans[x]=mx;
        }
        else
        {
            int r=(mx-mn)/2;
            int lalal=0;
            it=s1.lower_bound(r+1); 
            /*if (x==1)
            {
                printf("YES:%d mn:%d mx:%d r:%d %d\n",x,mn,mx,r,*it);
                //print();
            }*/
            //printf("YES:%d %d %d %d\n",x,*(--it),mn,fa);
            int g=n;
            //printf("lalal:%d\n",*it);
            if (it!=s1.end()) g=min(g,max(mn+(*it),mx-(*it)));
            if (it!=s1.begin()) 
            {
                it--;
                g=min(g,max(mn+(*it),mx-(*it)));
            }
            ans[x]=max(o,g);
        }
        for (int u=last[x];u!=-1;u=e[u].last)
        {
            int y=e[u].y;
            if (y==son[x]||y==fa) continue;
            Ins(y,x);
        }
    }
    s1.insert(tot[x]);
    it=s2.lower_bound(tot[x]);s2.erase(it);
    return ;
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    scanf("%d",&n);
    for (int u=1;u<=n;u++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x==0) rt=y;
        else    {init(x,y);init(y,x);}
    }
    dfs(rt,0);
    dfs1(rt,0);
//  printf("ans:%d\n",ans[4]);
    for (int u=1;u<=n;u++)
        printf("%d\n",ans[u]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36797743/article/details/80855295