【CF768G】The Winds of Winter 可持久化线段树 DFS序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ez_yww/article/details/78288330

题目大意

  给定一棵n个点的树,对于树上每个结点,将它删去,然后可以将得到的森林中任意一个点与其父亲断开并连接到另一颗树上,对每一个点求出森林中所有树size最大值的最小值。

  n100000

题解

  首先用DFS序+可持久化线段树求出删掉这个点后剩下的联通块的大小的最大值max、次大值sec、最小值min。这里要维护两棵可持久化线段树,一棵是DFS序前缀的,一棵是从根到每个点的。

  那么肯定是在最大的连通块上切下一块接到最小的连通块上。

  假设切下的大小为x,那么答案是max(maxx,min+x,sec)。这个的图像是带一个向下的尖角的,这个尖角的位置为max+min2。所以我们要切下来的x就是maxmin2。我们只需要在对应的可持久化线段树上找这个值的前驱和后继并统计答案。

  切下来的部分有三种可能:

   1.在x的子树内,可以直接统计答案

   2.在x的子树外且不包含x到根的点,可以直接统计答案

   3.在x的子树外切包含根到x的点,查询到的子树大小要减掉sizex

  时间复杂度:O(nlogn)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
namespace sgt
{
    int rt1[100010];
    int rt2[100010];
    struct node
    {
        int lc,rc;
        int s;
        node()
        {
            lc=rc=s=0;
        }
    };
    node a[10000010];
    int cnt=0;
    int insert(int p1,int x,int l,int r)
    {
        int p=++cnt;
        a[p]=a[p1];
        a[p].s++;
        if(l==r)
            return p;
        int mid=(l+r)>>1;
        if(x<=mid)
            a[p].lc=insert(a[p].lc,x,l,mid);
        else
            a[p].rc=insert(a[p].rc,x,mid+1,r);
        return p;
    }
    int suf(int p1,int p2,int p3,int p4,int x,int l,int r)//p1+p3-p2-p4
    {
        int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
        if(!s)
            return 0x3fffffff;
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        int ls=a[a[p1].lc].s+a[a[p3].lc].s-a[a[p4].lc].s-a[a[p2].lc].s;
        if(x<=mid&&ls)
        {
            int lans=suf(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,x,l,mid);
            if(lans!=0x3fffffff)
                return lans;
        }
        return suf(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,x,mid+1,r);
    }
    int pre(int p1,int p2,int p3,int p4,int x,int l,int r)
    {
        int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
        if(!s)
            return 0;
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        int rs=a[a[p1].rc].s+a[a[p3].rc].s-a[a[p4].rc].s-a[a[p2].rc].s;
        if(x>mid&&rs)
        {
            int rans=pre(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,x,mid+1,r);
            if(rans)
                return rans;
        }
        return pre(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,x,l,mid);
    }
    int getmax(int p1,int p2,int p3,int p4,int l,int r)
    {
        int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
        if(!s)
            return 0;
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        int rs=a[a[p1].rc].s+a[a[p3].rc].s-a[a[p4].rc].s-a[a[p2].rc].s;
        if(rs)
            return getmax(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,mid+1,r);
        return getmax(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,l,mid);
    }
    int getmin(int p1,int p2,int p3,int p4,int l,int r)
    {
        int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
        if(!s)
            return 0x3fffffff;
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        int ls=a[a[p1].lc].s+a[a[p3].lc].s-a[a[p4].lc].s-a[a[p2].lc].s;
        if(ls)
            return getmin(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,l,mid);           
        return getmin(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,mid+1,r);
    }
}
using sgt::rt1;
using sgt::rt2;
using sgt::insert;
using sgt::suf;
using sgt::pre;
using sgt::getmax;
using sgt::getmin;
list<int> l[100010];
int f[100010];
int st[100010];
int ed[100010];
int s[100010];
int w[100010];
int ti;
int n;
void dfs1(int x)
{
    st[x]=++ti;
    w[ti]=x;
    s[x]=1;
    for(auto v:l[x])
    {
        dfs1(v);
        s[x]+=s[v];
    }
    ed[x]=ti;
}
int update(int &a,int &b,int &c)
{
    if(c>=a)
    {
        b=a;
        a=c;
        return 1;
    }
    else
    {
        b=max(b,c);
        return 2;
    }
    return 0;
}
int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d",&n);
    int rt,x,y;
    int i;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        if(x)
        {
            l[x].push_back(y);
            f[y]=x;
        }
        else
            rt=y;
    }
    dfs1(rt);
    for(i=1;i<=n;i++)
    {
        x=w[i];
        rt2[x]=insert(rt2[f[x]],s[x],1,n);
        rt1[i]=insert(rt1[i-1],s[x],1,n);
    }
    for(i=1;i<=n;i++)
    {
        int mx=0,sec=0,mi=0x7fffffff;
        int s1,s2,s3,s4,ans;
        int mv;

        for(auto v:l[i])
        {
            s1=s[v];
            if(update(mx,sec,s1)==1)
            {
                s4=1;
                mv=v;
            }
            mi=min(mi,s1);
        }
        s1=n-s[i];
        if(s1)
        {
            if(update(mx,sec,s1)==1)
                s4=2;
            mi=min(mi,s1);
        }
        ans=0x7fffffff;
        int mid=(mi+mx+1)>>1;
        int s5=mx-mid;
        if(i==1)
            int xxx=1;
        ans=min(ans,mx);
        if(s4==1)
        {
            s1=pre(rt1[ed[mv]],rt1[st[mv]-1],0,0,s5,1,n);
            s2=suf(rt1[ed[mv]],rt1[st[mv]-1],0,0,s5,1,n);
            ans=min(ans,max(sec,max(mi+s1,mx-s1)));
            ans=min(ans,max(sec,max(mi+s2,mx-s2)));
        }
        else if(s4==2)
        {
            s1=pre(rt2[f[i]],0,0,0,s5+s[i],1,n);
            s2=suf(rt2[f[i]],0,0,0,s5+s[i],1,n);
            if(s1)
                s1-=s[i];
            if(s2!=0x3fffffff)
                s2-=s[i];
            ans=min(ans,max(sec,max(mi+s1,mx-s1)));
            ans=min(ans,max(sec,max(mi+s2,mx-s2)));
            s1=pre(rt1[st[i]-1],rt1[ed[i]],rt1[n],rt2[f[i]],s5,1,n);
            s2=suf(rt1[st[i]-1],rt1[ed[i]],rt1[n],rt2[f[i]],s5,1,n);
            ans=min(ans,max(sec,max(mi+s1,mx-s1)));
            ans=min(ans,max(sec,max(mi+s2,mx-s2)));
        }
        printf("%d\n",ans);
    }
    return 0;
}

没有更多推荐了,返回首页