(为啥我傻了吧唧的拆了点)
集合中的每一对点随即一个权值,然后再树上两个点分别异或这个权值,最后每次询问统计其中一边的子树的异或和是不是所有点对的权值的异或和即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<unordered_map>
#include<utility>
#include<assert.h>
#define uint unsigned long long
#define hv(x,y) ((uint)x*INT_MAX+y)
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define N 200010
#define M 300010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct Rand{
uint x;Rand(){x=1234567;}
inline uint operator()()
{ return x=((x*2333333333+998244353)%1000000007)^12379713; }
}rnd;
unordered_map<uint,int> eid;pii sid[M];int pf[N];
uint s[N],val[N],sv[N];int fa[N],ch[N][2],rev[N];
inline int gw(int x) { return ch[fa[x]][1]==x; }
inline int push_up(int x) { return s[x]=val[x]^s[ch[x][0]]^s[ch[x][1]],0; }
inline int push_down(int x)
{
if(ch[x][0]) rev[ch[x][0]]^=1;
if(ch[x][1]) rev[ch[x][1]]^=1;
return swap(ch[x][0],ch[x][1]),rev[x]=0;
}
inline int setc(int x,int y,int z)
{ if(!x) return fa[y]=0;ch[x][z]=y;if(y) fa[y]=x;return push_up(x); }
inline int rotate(int x)
{
int y=fa[x],z=fa[y],a=gw(x),b=gw(y),c=ch[x][a^1];
return swap(pf[x],pf[y]),setc(y,c,a),setc(x,y,a^1),setc(z,x,b);
}
inline int all_down(int x) { return (fa[x]?all_down(fa[x]):0),(rev[x]?push_down(x):0); }
inline int splay(int x,int tar=0)
{
for(all_down(x);fa[x]^tar;rotate(x))
if(fa[fa[x]]) rotate((gw(x)^gw(fa[x]))?x:fa[x]);
return 0;
}
inline int expose(int x)
{
splay(x);int y=ch[x][1];if(!y) return 0;
return pf[y]=x,fa[y]=ch[x][1]=0,val[x]^=s[y],push_up(x);
}
inline int splice(int x)
{
splay(x);int y=pf[x];if(!y) return 0;
return expose(y),splay(y),val[y]^=s[x],setc(y,x,1),pf[x]=0,1;
}
inline int access(int x) { expose(x);while(splice(x));return 0; }
inline int evert(int x) { return access(x),splay(x),rev[x]^=1; }
inline int link(int x,int y) { return evert(x),splay(x),evert(y),splay(y),pf[y]=x,val[x]^=s[y],s[x]^=s[y],0; }
inline int cut(int x,int y) { return evert(x),access(y),splay(x),s[x]^=s[y],ch[x][1]=fa[y]=pf[y]=0; }
inline int update(int x,uint v) { return access(x),splay(x),val[x]^=v,s[x]^=v,0; }
inline uint query(int x,int y,uint v=0) { return cut(x,y),evert(x),splay(x),v=s[x],link(x,y),v; }
int main()
{
int Test_id=inn(),n=inn(),m=inn(),sc=0;uint tot_val=0;
for(int i=1,x,y,c=n;i<n;i++)
x=inn(),y=inn(),eid[hv(x,y)]=eid[hv(y,x)]=++c,link(x,c),link(c,y);
while(m--)
{
int opt=inn(),x,y,u,v,c;
if(opt==1) x=inn(),y=inn(),u=inn(),v=inn(),c=eid[hv(x,y)],
cut(x,c),cut(c,y),link(u,c),link(c,v),eid[hv(u,v)]=eid[hv(v,u)]=c;
else if(opt==2) x=inn(),y=inn(),sid[++sc]=mp(x,y),
sv[sc]=rnd(),update(x,sv[sc]),update(y,sv[sc]),tot_val^=sv[sc];
else if(opt==3) c=inn(),x=sid[c].fir,y=sid[c].sec,update(x,sv[c]),update(y,sv[c]),tot_val^=sv[c];
else x=inn(),y=inn(),printf("%s\n",query(x,eid[hv(x,y)])==tot_val?"YES":"NO");
}
return Test_id-Test_id+0;
}