共价大爷游长沙 lct 维护子树信息
这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边。
某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的。
现在我们要判断所有的路径是不是都经过 u -> v 我们以u为根节点, 如果所有的路劲的起点 有且仅有一个点在 v 的子树内 我们就可以知道这个边是合法的。
那么我们每次增加路劲之后, 都在2个端点都亦或上某一个值, 每次判断的时候都判断这个v的子树内整颗树的亦或和是不是等于整体亦或和。如果是 那就说明合法。
现在我们用lct维护这个树。
在这个地方我们需要用lct维护子树信息。
普通的lct是维护一条链的。
lct维护子树的话, 我们需要新开一个状态 存下所有的 非偏爱子节点的 的值。
每次切换偏爱子节点的时候, 假设 u 的偏爱子节点为 v 现在转变成x。
那我们就需要把 x的值从非偏爱中取出, 然后在把u的值放入。
这样我们就维护好了这个东西。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12 #define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 5e5 + 100; 20 struct Node{ 21 int rev, rt; 22 int son[2], pre; 23 int sum, vsum, key; 24 void init(){ 25 rt = 1; rev = pre = son[0] = son[1] = 0; 26 sum = vsum = key = 0; 27 } 28 }tr[N]; 29 void Push_Rev(int x){ 30 if(!x) return ; 31 swap(lch(x), rch(x)); 32 tr[x].rev ^= 1; 33 } 34 void Push_Up(int x){ 35 if(!x) return ; 36 tr[x].sum = tr[x].key ^ tr[lch(x)].sum ^ tr[rch(x)].sum ^ tr[x].vsum; 37 } 38 void Push_Down(int x){ 39 if(tr[x].rev){ 40 tr[x].rev = 0; 41 Push_Rev(lch(x)); 42 Push_Rev(rch(x)); 43 } 44 } 45 void Rev(int x){ 46 if(!tr[x].rt) Rev(tr[x].pre); 47 Push_Down(x); 48 } 49 void rotate(int x){ 50 if(tr[x].rt) return; 51 int y = tr[x].pre, z = tr[y].pre; 52 int k = (rch(y) == x); 53 tr[y].son[k] = tr[x].son[k^1]; 54 tr[tr[y].son[k]].pre = y; 55 tr[x].son[k^1] = y; 56 tr[y].pre = x; 57 tr[x].pre = z; 58 if(tr[y].rt) tr[y].rt = 0, tr[x].rt = 1; 59 else tr[z].son[rch(z) == y] = x; 60 Push_Up(y); 61 } 62 void Splay(int x){ 63 Rev(x); 64 while(!tr[x].rt){ 65 int y = tr[x].pre, z = tr[y].pre; 66 if(!tr[y].rt){ 67 if(( x == rch(y) ) != (y == rch(z))) rotate(y); 68 else rotate(x); 69 } 70 rotate(x); 71 } 72 Push_Up(x); 73 } 74 void Access(int x){ 75 int y = 0; 76 do{ 77 Splay(x); 78 tr[rch(x)].rt = 1; 79 tr[x].vsum ^= tr[rch(x)].sum; 80 rch(x) = y; 81 tr[x].vsum ^= tr[rch(x)].sum; 82 tr[y].rt = 0; 83 Push_Up(x); 84 y = x; 85 x = tr[x].pre; 86 }while(x); 87 } 88 void Make_rt(int x){ 89 Access(x); 90 Splay(x); 91 Push_Rev(x); 92 } 93 void link(int u, int v){ 94 Make_rt(u); 95 Access(v); 96 Splay(v); 97 tr[u].pre = v; 98 tr[v]. 99 vsum ^= tr[u].sum; 100 Push_Up(v); 101 } 102 void cut(int u, int v){ 103 Make_rt(u); 104 Access(v); 105 Splay(v); 106 tr[lch(v)].pre = 0; 107 tr[lch(v)].rt = 1; 108 tr[v].pre = 0; 109 lch(v) = 0; 110 Push_Up(v); 111 } 112 int a[N], b[N], c[N]; 113 int main(){ 114 int n, m; 115 scanf("%d%d%d", &n, &n, &m); 116 int x, y; 117 for(int i = 1; i <= n; i++) 118 tr[i].init(); 119 for(int i = 1; i < n; i++){ 120 scanf("%d%d", &x, &y); 121 link(x, y); 122 } 123 int op, u, v, tot = 0; 124 int jud = 0; 125 for(int i = 1; i <= m; i++){ 126 scanf("%d", &op); 127 if(op == 1){ 128 scanf("%d%d%d%d", &x, &y, &u, &v); 129 cut(x, y); 130 link(u, v); 131 } 132 if(op == 2){ 133 ++tot; 134 scanf("%d%d", &a[tot], &b[tot]); 135 x = a[tot], y = b[tot]; 136 c[tot] = rand()>>15|rand(); 137 Make_rt(x); 138 tr[x].sum ^= c[tot]; 139 tr[x].key ^= c[tot]; 140 Make_rt(y); 141 tr[y].sum ^= c[tot]; 142 tr[y].key ^= c[tot]; 143 jud ^= c[tot]; 144 } 145 if(op == 3){ 146 scanf("%d", &v); 147 x = a[v], y = b[v], u = c[v]; 148 Make_rt(x); 149 tr[x].sum ^= u; 150 tr[x].key ^= u; 151 Make_rt(y); 152 tr[y].sum ^= u; 153 tr[y].key ^= u; 154 jud ^= u; 155 } 156 if(op == 4){ 157 scanf("%d%d", &x, &y); 158 Make_rt(x); 159 Access(y); 160 Splay(x); 161 if(jud == tr[y].sum) puts("YES"); 162 else puts("NO"); 163 } 164 } 165 return 0; 166 }