题目大意:自己看题目吧。。
这题真是机巧。
为每一条路径随机一个权值,记录每条边上的异或值。对于一条删边,将其权值异或到新的路径上,用LCT维护。
判断一条边是否被所有路径经过只用判断异或和是否相等就行了。
中间要用map等小技巧,还是比较简单的,不用维护任何东西。但是难想。第一次写随机数冲突了,srand(num)比较可行。还有就是每次询问之前别忘了splay一下。
还有一种维护子树异或和的做法,这里就不讲了。(这也是基础的操作啊)
推荐去看kekxy的博客。
#include
#define maxn 200010
#define M1 998244353
#define M2 1000000007
#define M3 1333333331
using namespace std;
int ID, cnt, n, m, ToT, VAL;
map <long long, int> M;
int X[maxn], Y[maxn], Z[maxn];
struct Tnode{
Tnode *son[2], *fa;
int parent, val, add;
bool rev;
int Get_d(){return fa->son[1] == this;}
void Connect(Tnode *now, int d){(son[d] = now)->fa = this;}
void Down(){
if(rev){
swap(son[0], son[1]);
if(son[0]) son[0]->rev ^= 1;
if(son[1]) son[1]->rev ^= 1;
rev = false;
}
if(add){
if(son[0]) son[0]->val ^= add, son[0]->add ^= add;
if(son[1]) son[1]->val ^= add, son[1]->add ^= add;
add = 0;
}
}
}tree[maxn], *Node[maxn];
Tnode *NewTnode(){
tree[cnt].fa = tree[cnt].son[0] = tree[cnt].son[1] = NULL;
tree[cnt].parent = tree[cnt].add = 0;
tree[cnt].rev = false;
return tree+cnt++;
}
void Zig(Tnode *now){
Tnode *last = now->fa;
int d = now->Get_d();
if(now->son[!d]) last->Connect(now->son[!d], d);
else last->son[d] = NULL;
if(last->fa) last->fa->Connect(now, last->Get_d());
else now->fa = NULL;
now->Connect(last, !d);
now->parent = last->parent;
last->parent = 0;
}
void Splay(Tnode *now){
Tnode *last;
while(now->fa){
last = now->fa;
if(last->fa) last->fa->Down();
last->Down(); now->Down();
if(last->fa) (now->Get_d() ^ last->Get_d()) ? Zig(now) : Zig(last);
Zig(now);
}
if(!now->fa) now->Down();
}
void Access(int x){
Splay(Node[x]);
if(Node[x]->son[1]){
Node[x]->son[1]->fa = NULL;
Node[x]->son[1]->parent = x;
Node[x]->son[1] = NULL;
}
int y = Node[x]->parent;
while(y){
Splay(Node[y]);
if(Node[y]->son[1]){
Node[y]->son[1]->fa = NULL;
Node[y]->son[1]->parent = y;
Node[y]->son[1] = NULL;
}
Node[y]->Connect(Node[x], 1);
Node[x]->parent = 0;
x = y;
y = Node[x]->parent;
}
}
void Evert(int x){
Access(x);
Splay(Node[x]);
Node[x]->rev ^= 1;
}
void Link(int x, int y){
Evert(x);
Node[x]->parent = y;
}
void Cut(int x, int y){
Evert(x);
Access(y);
Splay(Node[x]);
Node[x]->son[1]->fa = NULL;
Node[x]->son[1] = NULL;
}
void Update(int x, int y, int val){
Evert(x);
Access(y);
Splay(Node[x]);
Node[x]->val ^= val;
Node[x]->add ^= val;
}
int Query(int x, int y){
int edge = M[1LL*x*(n-1)+y];
Splay(Node[edge]);
return Node[edge]->val;
}
int Get(){
VAL = (1LL * VAL * M1 + M2) % M3;
return VAL;
}
int main(){
scanf("%d", &ID);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) Node[i] = NewTnode();
int a, b;
for(int i = 1; i < n; i++){
Node[i+n] = NewTnode();
scanf("%d%d", &a, &b);
M[1LL*a*(n-1)+b] = M[1LL*b*(n-1)+a] = i + n;
Link(a, i+n);
Link(i+n, b);
}
int op, u, v;
for(int i = 1; i <= m; i++){
scanf("%d", &op);
if(op == 1){
scanf("%d%d%d%d", &a, &b, &u, &v);
int edge = M[1LL*a*(n-1)+b];
Splay(Node[edge]);
int val = Node[edge]->val;
Cut(a, edge);
Cut(edge, b);
Node[edge]->fa = Node[edge]->son[0] = Node[edge]->son[1] = NULL;
Node[edge]->val = Node[edge]->parent = 0;
Node[edge]->rev = false;
Link(u, edge);
Link(edge, v);
M[1LL*u*(n-1)+v] = M[1LL*v*(n-1)+u] = edge;
Update(a, b, val);
}
else if(op == 2){
scanf("%d%d", &a, &b);
int val = Get();
ToT ^= val;
Update(a, b, val);
X[++X[0]] = a; Y[X[0]] = b; Z[X[0]] = val;
}
else if(op == 3){
scanf("%d", &a);
ToT ^= Z[a];
Update(X[a], Y[a], Z[a]);
}
else{
scanf("%d%d", &a, &b);
int res = Query(a, b);
if(res == ToT) puts("YES");
else puts("NO");
}
}
return 0;
}