【UOJ #207】共价大爷游长沙

Description

有一棵树,会改变它的形态。
有一个路径集合,初始为空,路径集合会被更改。
询问操作是询问一条边是否被路径集合所有路径经过。
n<=100000

Analysis

对于一条边(x,y),如果所有路径都经过它,当且仅当所有路径中的仅一个端点在以x为根,y的子树内
我们对每一个路径随机一个权值,然后每次加入删除路径时,将两个段点的点权异或上这个权值,然后用动态树维护子树权值异或和,每次询问对应子树内的权值异或和是否是当前所有路径的权值异或和
Orz myy

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,b,a) for(int i=b;i>=a;--i)
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
char ch;
void read(int &n){n=0;int p=1;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';n*=p;}
const int N=1e5+5,M=3e5+5;
int n,m,stk[N],f[N],p[N],a[N][2],key[N],sum[N],vir[N];
bool rev[N];
int pd(int x){return x==a[f[x]][1];}
void update(int x)
{
    sum[x]=key[x]^sum[a[x][0]]^sum[a[x][1]]^vir[x];
}
void turn(int x)
{
    swap(a[x][0],a[x][1]);
    rev[x]^=1;
}
void down(int x)
{
    if(!rev[x]) return;
    turn(a[x][0]);turn(a[x][1]);
    rev[x]=0;
}
void remove(int x,int y)
{
    for(;x!=y;x=f[x]) stk[++stk[0]]=x;
    while(stk[0]) down(stk[stk[0]--]);
}
void rotate(int x)
{
    int y=f[x],z=pd(x);
    f[x]=f[y];
    if(f[y]) a[f[y]][pd(y)]=x;
    else p[x]=p[y],p[y]=0;
    a[y][z]=a[x][1-z];
    if(a[x][1-z]) f[a[x][1-z]]=y;
    f[y]=x,a[x][1-z]=y;
    update(y);
}
void splay(int x,int y)
{
    remove(x,y);
    for(;f[x]!=y;rotate(x))
        if(f[f[x]]!=y) rotate(pd(x)==pd(f[x])?f[x]:x);
    update(x);
}
void access(int x)
{
    for(int y=0;x;y=x,x=p[x])
    {
        splay(x,0);
        f[a[x][1]]=0,p[a[x][1]]=x;
        vir[x]^=sum[a[x][1]];
        a[x][1]=y,f[y]=x,p[y]=0;
        vir[x]^=sum[y];
        update(x);
    }
}
void makeroot(int x)
{
    access(x);
    splay(x,0);
    turn(x);
}
void link(int x,int y)
{
    makeroot(x);makeroot(y);
    p[x]=y;
    vir[y]^=sum[x];
}
void cut(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y,0);
    f[x]=0,a[y][0]=0;
    update(y);
}
int query(int x)
{
    access(x);
    return key[x]^vir[x];
}
struct Path
{
    int x,y,z;
    Path(int _x=0,int _y=0,int _z=0):x(_x),y(_y),z(_z){}
}path[M];
int main()
{
    srand(19260817);rand();
    int ID,T,tp,x,y,z,u,v,val=0;
    read(ID),read(n),read(T);
    fo(i,1,n-1) read(x),read(y),link(x,y);
    while(T--)
    {
        read(tp),read(x);
        if(tp==1)
        {
            read(y),read(u),read(v);
            cut(x,y);
            link(u,v);
        }
        else
        if(tp==2)
        {
            read(y);
            path[++m]=Path(x,y,(unsigned int)(rand()*rand()+rand())%int(2e9));
            val^=path[m].z;
            makeroot(x);key[x]^=path[m].z;update(x);
            makeroot(y);key[y]^=path[m].z;update(y);
        }
        else
        if(tp==3)
        {
            int id=x;
            x=path[id].x,y=path[id].y,z=path[id].z;
            val^=z;
            makeroot(x);key[x]^=z;update(x);
            makeroot(y);key[y]^=z;update(y);
        }
        else
        {
            read(y);makeroot(y);
            makeroot(x);
            int t=query(y);
            puts(t==val?"YES":"NO");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值