维护一个数据结构,要求对树支持以下操作:
myy的题,感觉好神啊,只会做50分。
考虑询问的边 (x,y) ( x , y ) 被所有点对路径经过相当于以 x x 为根时,所有点对都恰有一个端点在以 y y 的子树中。
所以对每个点对随机一个权值,并让端点异或上这个权值。每次询问时查询以 y y 为根的子树异或和是否等于总异或和即可。
#include
using namespace std;
const int maxn = 100005, maxm = 300005;
int n, m, Id, S, x[maxm], y[maxm], z[maxm], cnt;
int ch[maxn][2], vsum[maxn], sum[maxn], f[maxn], val[maxn], rev[maxn];
int Rand(int l,int r)
{
double dou=1.0*rand()/RAND_MAX;
return dou*(r-l+1)+l;
}
#define isroot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)
#define get(x) (ch[f[x]][1] == x)
#define update(x) sum[x] = vsum[x] ^ val[x] ^ sum[ch[x][0]] ^ sum[ch[x][1]]
inline void rotate(int x)
{
int fa = f[x], gfa = f[fa], k = get(x);
if(!isroot(fa)) ch[gfa][get(fa)] = x;
ch[fa][k] = ch[x][k ^ 1]; f[ch[x][k ^ 1]] = fa;
ch[x][k ^ 1] = fa; f[fa] = x;
f[x] = gfa;
update(fa); update(x);
}
int stk[maxn], top;
inline void pushdown(int x)
{
if(!x || !rev[x]) return ;
if(ch[x][0]) rev[ch[x][0]] ^= 1;
if(ch[x][1]) rev[ch[x][1]] ^= 1;
swap(ch[x][0], ch[x][1]); rev[x] = 0;
}
inline void splay(int x)
{
stk[top = 1] = x;
while(!isroot(x)) stk[++top] = x = f[x];
while(top) pushdown(stk[top--]);
x = stk[1];
while(!isroot(x)) {
int fa = f[x];
if(!isroot(fa)) get(fa) ^ get(x) ? rotate(x) : rotate(fa);
rotate(x);
}
update(x);
}
inline void access(int x)
{
for(int y = 0; x; y = x, x = f[x]) {
splay(x); vsum[x] ^= sum[ch[x][1]] ^ sum[y]; ch[x][1] = y;
update(x);
}
}
inline void make_root(int x) {access(x); splay(x); rev[x] ^= 1;}
inline void link(int x, int y) {make_root(x); make_root(y); vsum[y] ^= sum[x]; f[x] = y;}
inline void cut(int x, int y) {make_root(x); access(y); splay(y); f[x] = ch[y][0] = 0; update(x); update(y);}
inline void insert(int u, int v, int w)
{
make_root(u); splay(u); val[u] ^= w; sum[u] ^= w;
make_root(v); splay(v); val[v] ^= w; sum[v] ^= w;
}
inline bool query(int x, int y)
{
make_root(x); access(y); splay(y);
return sum[x] == S;
}
int main()
{
freopen("visit.in", "r", stdin);
freopen("visit.out", "w", stdout);
scanf("%d%d%d", &Id, &n, &m);
for(int u, v, i = 1; i < n; ++i)
scanf("%d%d", &u, &v), link(u, v);
for(int opt, u, v, w, i = 1; i <= m; ++i) {
scanf("%d", &opt);
if (opt == 1) {
scanf("%d%d", &u, &v); cut(u, v);
scanf("%d%d", &u, &v); link(u, v);
}else if (opt == 2) {
scanf("%d%d", &u, &v); w = Rand(1, 1000000000); S ^= w;
insert(u, v, w);
++cnt; x[cnt] = u; y[cnt] = v; z[cnt] = w;
}else if (opt == 3) {
scanf("%d", &u); insert(x[u], y[u], z[u]); S ^= z[u];
}else if (opt == 4) {
scanf("%d%d", &u, &v);
if(query(u, v)) puts("YES");
else puts("NO");
}
}
return 0;
}