BZOJ3843: ZCC loves Army

把树转成左儿子右兄弟的那种二叉树的形式
发现一个点能且仅能给他的子树传递order,询问3就变成了询问一个点到根有多少个点
对于传递message,可以给每个点定一个编号0的虚儿子,给他赋权1,就变成了询问两点间路径的权值和,注意要特判一个点是另一个点的祖先的情况,bzoj上的数据有误,不判这个才能过,hdu上的数据是对的可以去那里交
对于操作1,把某个人的一段儿子截下来,可以用n棵splay处理每个人的孩子链表
然后就都是splay,LCT的常规操作了

code:(bz上的AC代码,注释掉了判祖先的那部分)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 300010;

int n,m;
int t[maxn],tp;
struct Splay
{
    int son[maxn][2],fa[maxn],root[maxn],s[maxn],siz[maxn];
    void pushup(const int x){siz[x]=s[x]+siz[son[x][0]]+siz[son[x][1]];}
    int build(const int y,const int l,const int r)
    {
        int mid=l+r>>1,x=t[mid]; fa[x]=y;
        if(l==r) return x;
        if(l!=mid) son[x][0]=build(x,l,mid-1);
        if(mid!=r) son[x][1]=build(x,mid+1,r);
        pushup(x);
        return x;
    }
    void rotate(int x,int &k)
    {
        int y=fa[x],z=fa[y];
        if(y==k) k=x;
        else if(z) son[z][son[z][1]==y]=x;
        fa[x]=z;
        int l=son[y][1]==x;
        fa[son[y][l]=son[x][!l]]=y;
        fa[son[x][!l]=y]=x;
        pushup(y);
    }
    void splay(int x,int &k)
    {
        for(;x!=k;rotate(x,k))
        {
            int y=fa[x],z=fa[y];
            if(y!=k)
            {
                if((son[y][1]==x)^(son[z][1]==y)) rotate(x,k);
                else rotate(y,k);
            }
        }pushup(x);
    }
    int find_(const int r,int k)
    {
        int x=root[r];
        while(1)
        {
            if(k<=siz[son[x][0]]) 
            {
                if(!son[x][0]) return x;
                x=son[x][0];
            }
            else if(k==siz[son[x][0]]+s[x]) return x;
            else
            {
                if(!son[x][1]) return x;
                k-=siz[son[x][0]]+s[x];
                x=son[x][1];
            }
        }
    }
}S;
struct LinkCutTree
{
    int s1[maxn],s2[maxn],c1[maxn],c2[maxn];
    int son[maxn][2],fa[maxn];
    void pushup(const int x)
    {
        c1[x]=s1[x]+c1[son[x][0]]+c1[son[x][1]];
        c2[x]=s2[x]+c2[son[x][0]]+c2[son[x][1]];
    }
    bool isroot(const int x) { return (son[fa[x]][0]!=x&&son[fa[x]][1]!=x); }
    void rotate(const int x)
    {
        int y=fa[x],z=fa[y];
        if(!isroot(y)) son[z][son[z][1]==y]=x;
        fa[x]=z;
        int l=son[y][1]==x;
        fa[son[y][l]=son[x][!l]]=y;
        fa[son[x][!l]=y]=x;
        pushup(y);
    }
    void splay(const int x)
    {
        for(;!isroot(x);rotate(x))
        {
            int y=fa[x],z=fa[y];
            if(!isroot(y))
            {
                if((son[y][1]==x)^(son[z][1]==y)) rotate(x);
                else rotate(y);
            }
        }pushup(x);
    }
    void access(int x)
    {
        int y=0;
        for(;x;y=x,x=fa[x])
        {
            splay(x); son[x][1]=y; pushup(x);
        }
    }
    void Link(int a,int b)
    {
        access(b); splay(b); fa[b]=a;
    }
    void Cut(int a)
    {
        access(a); splay(a);
        son[a][0]=fa[son[a][0]]=0; pushup(a);
    }
    int LCA(int a,int b)
    {
        access(b);
        int y=0;
        for(int x=a;x;y=x,x=fa[x])
        {
            splay(x); son[x][1]=y; pushup(x);
            if(fa[x]==0) return x;
        }
    }
    int go(int x,int to)
    {
        while(son[x][to]) x=son[x][to];
        return x;
    }
    int las(int a,int b)
    {
        access(b); splay(a);
        return go(son[a][1],0);
    }
    int sum1(int x)
    {
        access(x); splay(x);
        return c1[son[x][0]]+s1[x];
    }
    int sum2(int x)
    {
        access(x); splay(x);
        return c2[son[x][0]];
    }
}LCT;


void Move(const int r1,int p,int c,const int r2,int q)
{
    c=p+c-1;
    int ll=S.find_(r1,p-1),l=S.find_(r1,p);
    int r=S.find_(r1,c),rr=S.find_(r1,c+1);
    int tol=S.find_(r2,q),tor=S.find_(r2,q+1);

    LCT.Cut(l); if(rr<=n) LCT.Cut(rr),LCT.Link(ll,rr);
    if(tor<=n) LCT.Cut(tor),LCT.Link(r,tor);
    LCT.Link(tol,l);

    S.splay(ll,S.root[r1]); S.splay(rr,S.son[ll][1]);
    int y=S.son[rr][0]; S.son[rr][0]=0; S.splay(rr,S.root[r1]);
    S.splay(tol,S.root[r2]); S.splay(tor,S.son[tol][1]);
    S.son[tor][0]=y; S.fa[y]=tor; S.splay(y,S.root[r2]);
}
int solve1(const int x,const int y)
{
    int ff=LCT.LCA(x,y);
    if(ff==x) 
    {
        int a1=LCT.sum1(y),a2=LCT.sum1(x);
        int ans=a1-a2+1;
        //if(LCT.las(x,y)>n) ans--;
        return ans;
    }
    else if(ff==y) 
    {
        int a1=LCT.sum1(x),a2=LCT.sum1(y);
        int ans=a1-a2+1;
        //if(LCT.las(y,x)>n) ans--;
        return ans;
    }
    else
    {
        int a1=LCT.sum1(x);
        int a2=LCT.sum1(y);
        int a3=2*LCT.sum1(ff);
        return a1+a2-a3+1;
    }
}
int solve2(const int x) { return LCT.sum2(x); }

int main()
{
    read(n); read(m);
    for(int i=1;i<=n;i++) S.s[i]=S.siz[i]=1;
    for(int i=1;i<=n;i++)
    {
        LCT.s2[i]=LCT.c2[i]=1;
        LCT.s1[n+i]=LCT.c1[n+i]=1;
        LCT.Link(i,n+i);
        int cc,la; read(cc);
        la=t[tp=1]=n+i;
        while(cc--)
        {
            int x; read(x); t[++tp]=x;
            LCT.Link(la,x); la=x;
        }
        t[++tp]=n+n+i;
        S.root[i]=S.build(0,1,tp);
    }
    while(m--)
    {
        int ki; read(ki);
        if(ki==1)
        {
            int x,p,c,y,q; 
            read(x),read(p),read(c);
            read(y),read(q);
            Move(x,p,c,y,q);
        }
        else if(ki==2)
        {
            int x,y; read(x); read(y);
            printf("%d\n",solve1(x,y)-1);
        }
        else
        {
            int x; read(x);
            printf("%d\n",solve2(x));
        }
    }

    return 0;
}

你可能感兴趣的:(BZOJ,多校,LCT,splay)