【uoj207】 共價大爺遊長沙

http://uoj.ac/problem/207 (題目連接)node

題意

  給出一棵無根樹,4種操做:在路徑集合中加入一條路徑,在路徑集合中刪除一條路徑,刪一條邊加一條邊,查詢一條邊是否被集合中全部路徑通過。ios

Solution

  將路徑端點同時異或上一個值,那麼若是一條路徑被通過,那麼它的子樹中點的異或和必定等於全部路徑的異或和。spa

  考慮如何用LCT維護這種可加減的子樹信息。blog

  對於詢問,咱們將詢問的點access一下,那麼它的全部虛兒子就是它在真實的樹中的全部兒子了。get

  對於會使輕重邊切換的操做:access,link,cut。注意同時更新虛兒子信息。string

細節

  link的時候,兩端點都要makeroot,不然做爲父親的一點沒法更新祖先的信息。it

代碼

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf (1ll<<30)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
 
const int maxn=300010;
int S,n,m,id,tot,fa[maxn];
 
struct edge {int u,v,w;}e[maxn];
struct node {
    int son[2],val,sum,rev;  //val=x+虛兒子;sum=val+實兒子
    int& operator [] (int x) {return son[x];}
}tr[maxn];
 
void reverse(int x) {
    swap(tr[x][0],tr[x][1]);tr[x].rev^=1;
}
void pushdown(int x) {
    if (tr[fa[x]][0]==x || tr[fa[x]][1]==x) pushdown(fa[x]);
    if (tr[x].rev) {
        if (tr[x][0]) reverse(tr[x][0]);
        if (tr[x][1]) reverse(tr[x][1]);
        tr[x].rev^=1;
    }
}
void pushup(int x) {
    tr[x].sum=tr[tr[x][0]].sum^tr[tr[x][1]].sum^tr[x].val;
}
void rotate(int x) {
    int y=fa[x],z=fa[y],l,r;
    l=tr[y][1]==x;r=l^1;
    if (tr[z][0]==y || tr[z][1]==y) tr[z][tr[z][1]==y]=x;
    fa[tr[x][r]]=y;fa[x]=z;fa[y]=x;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    pushup(y);pushup(x);
}
void splay(int x) {
    pushdown(x);
    while (tr[fa[x]][0]==x || tr[fa[x]][1]==x) {
        int y=fa[x],z=fa[y];
        if (tr[z][0]==y || tr[z][1]==y) {
            if ((tr[z][0]==y) ^ (tr[y][0]==x)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x) {
    for (int y=0;x;y=x,x=fa[x]) {
        splay(x);tr[x].val^=tr[tr[x][1]].sum;
        tr[x].val^=tr[tr[x][1]=y].sum;
        pushup(x);
    }
}
void makeroot(int x) {
    access(x);splay(x);reverse(x);
}
void link(int x,int y) {
    makeroot(x);makeroot(y);  //必定要makeroot(y),不然沒法更新y所在的splay上祖先的信息
    fa[x]=y;tr[y].val^=tr[x].sum;
    pushup(y);
}
void cut(int x,int y) {
    makeroot(x);access(y);splay(y);
    fa[x]=tr[y][0]=0;pushup(y);
}
void modify(int x,int val) {
    access(x);splay(x);
    tr[x].val^=val;tr[x].sum^=val;
}
bool query(int x,int y) {
    makeroot(x);access(y);  //access之後,y在實樹上的兒子全爲它的虛兒子
    return tr[y].val==S ? 1 : 0;
}
 
int main() {
    scanf("%d%d%d",&id,&n,&m);
    for (int x,y,i=1;i<n;i++) {
        scanf("%d%d",&x,&y);
        link(x,y);
    }
    for (int op,x,y,z,i=1;i<=m;i++) {
        scanf("%d",&op);
        if (op==1) {
            scanf("%d%d",&x,&y);cut(x,y);
            scanf("%d%d",&x,&y);link(x,y);
        }
        if (op==2) {
            scanf("%d%d",&x,&y);
            e[++tot]=(edge){x,y,z=rand()};
            modify(x,z),modify(y,z);S^=z;
        }
        if (op==3) {
            scanf("%d",&x);S^=e[x].w;
            modify(e[x].u,e[x].w);modify(e[x].v,e[x].w);
        }
        if (op==4) {
            scanf("%d%d",&x,&y);
            puts(query(x,y) ? "YES" : "NO");
        }
    }
    return 0;
}
相關文章
相關標籤/搜索