UOJ#207: tour of Changsha by the co-founder (LCT maintains subtree information)

Problem surface
Question meaning: a tree requires to support adding and deleting edges, adding and deleting paths, and asks whether all paths pass through an edge.

At the beginning, I thought of maintaining the number of start points and end points in the Unicom block, as well as the number of path addition and subtraction, but there are counter examples.

It should be a routine I haven't heard of.
A random rp value for each path, XOR value at two points, maintenance of subtree XOR sum is good.

Another way is to XOR rp to the path. When deleting an edge, the whole path is exclusive of the rp value of the edge.
It seems random, but I didn't find this method very clever until I figured out why path + 1 was wrong.

For the deleted edge (u,v) and any edge E on the deleted path (u,v).
For the path passing through (u,v) before edge deletion, if it passes through E before edge deletion, then it will not pass through E after edge deletion, and vice versa.
It makes full use of the feature that the difference or the same is 0.

I haven't written LCT maintenance subtree information for a long time, so I wrote the first one.

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=200200;

int n,m,now,cnt;
int u[N],v[N],rp[N];

void read(int &hy)
{
    hy=0;
    char cc=getchar();
    while(cc<'0'||cc>'9')
    cc=getchar();
    while(cc>='0'&&cc<='9')
    {
        hy=(hy<<3)+(hy<<1)+cc-'0';
        cc=getchar();
    }
}

struct tree
{
    int a,aa;
    bool flip;
    tree *c[2],*pp,*f;
    int d(){return f->c[1]==this;}
    void sc(tree *x,int d){(c[d]=x)->f=this;}
}nil[N],*ro[N];

void down(tree *x)
{
    if(x->flip)
    {
        x->flip=0;
        swap(x->c[0],x->c[1]);
        x->c[0]->flip^=1;
        x->c[1]->flip^=1;
    }
}

void work(tree *x)
{
    if(x->f!=nil)
    work(x->f);
    down(x);
}

void up(tree *x)
{
    x->aa=x->a^x->c[0]->aa^x->c[1]->aa;
}

void zig(tree *x)
{
    int d=x->d();
    tree *y=x->f;
    y->sc(x->c[!d],d);
    if(y->f==nil)
    x->f=nil;
    else
    y->f->sc(x,y->d());
    x->sc(y,!d);
    x->pp=y->pp;
    y->pp=nil;
    up(y);
    up(x);
}

void splay(tree *x)
{
    work(x);
    for(tree *y;x->f!=nil;)
    {
        y=x->f;
        if(y->f!=nil)
        (x->d() ^ y->d()) ? zig(x) : zig(y);
        zig(x);
    }
}

void Access(tree *x)
{
    tree *y=nil;
    while(x!=nil)
    {
        splay(x);
        if(x->c[1]!=nil)
        {
            x->c[1]->f=nil;
            x->c[1]->pp=x;
            x->a^=x->c[1]->aa;
        }
        x->c[1]=y;
        if(y!=nil)
        y->f=x;
        x->a^=y->aa;

        up(x);
        y->pp=nil;
        y=x;
        x=x->pp;
    }
}

void Evert(tree *x)
{
    Access(x);
    splay(x);
    x->flip^=1;
}

void Link(tree *x,tree *y)
{
    Evert(x);
    splay(x);
    Access(y);
    splay(y);
    x->pp=y;
    y->a^=x->aa;
    up(y);
}

void Cut(tree *x,tree *y)
{
    Evert(x);
    Access(y);
    splay(x);
    x->c[1]->f=nil;
    x->c[1]=nil;
    up(x);
}

void BBQ(tree *x,int oi)
{
    Access(x);
    splay(x);
    x->a^=oi;
    up(x);
}

int main()
{
    srand(time(0));

    nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;

    cin>>n;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        nil[i]=nil[0];
        ro[i]=nil+i;
    }

    for(int i=1;i<n;i++)
    {
        int uu,vv;
        read(uu);
        read(vv);
        Link(ro[uu],ro[vv]);
    }

    for(int i=1;i<=m;i++)
    {
        int ops,uu,vv;
        read(ops);
        if(ops==1)
        {
            read(uu);
            read(vv);
            Cut(ro[uu],ro[vv]);
            read(uu);
            read(vv);
            Link(ro[uu],ro[vv]);
        }
        if(ops==2)
        {
            cnt++;
            rp[cnt]=rand()*rand();
            now^=rp[cnt];
            read(u[cnt]);
            read(v[cnt]);
            BBQ(ro[u[cnt]],rp[cnt]);
            BBQ(ro[v[cnt]],rp[cnt]);
        }
        if(ops==3)
        {
            read(uu);
            now^=rp[uu];
            BBQ(ro[u[uu]],rp[uu]);
            BBQ(ro[v[uu]],rp[uu]);
        }
        if(ops==4)
        {
            read(uu);
            read(vv);
            Evert(ro[uu]);
            Access(ro[vv]);
            splay(ro[vv]);
            if(ro[vv]->a==now)
            printf("YES\n");
            else
            printf("NO\n");
        }
    }

    return 0;
}

Posted on Sun, 03 May 2020 18:35:05 -0400 by kirannalla