隔壁尹神说树剖裸题
太巨了
先说一个~~(你M)~~nim游戏的性质就是所有堆的石子的数量Xor起来不等于0先手必胜,我也不知道咋证明
于是乎我们就可以大力维护树上的Xor路径,咋维护呢?先求dfs序,转化成区间问题,然后用树状数组维护一下就好了,查询的时候,求一条x–>rt的Xor路径,再求一条y–>rt的Xor路径,Xor一下,发现lca(x,y)以上就没了,但是少了一个val[lca]所以再Xor回来就好了,然后修改操作,先把这个点的权值在树状数组里删掉,改完之后,再加回去,实测比树剖快,而且dfs不会爆栈
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
const int M=5e5+50;
int n,m;
int a[M],s[M];
int dep[M],f[M][20];
int in[M],out[M],ti;
int to[M*2],nxt[M*2],head[M*2],cnt;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void adde(int x,int y)
{
to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;
to[++cnt]=x;nxt[cnt]=head[y];head[y]=cnt;
return ;
}
inline void dfs(int x,int fa)
{
in[x]=++ti;
f[x][0]=fa;dep[x]=dep[fa]+1;
for (int i=1;i<=18;i++)
f[x][i]=f[f[x][i-1]][i-1];
for (int i=head[x];i;i=nxt[i])
if (to[i]!=fa) dfs(to[i],x);
out[x]=ti;
return ;
}
inline int lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=18;i>=0;i--)
if (dep[f[x][i]]>=dep[y])
x=f[x][i];
if (x==y) return x;
for (int i=18;i>=0;i--)
if (f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void add(int p,int x)
{
for (int i=p;i<=n;i+=lowbit(i)) s[i]^=x;
return ;
}
inline int sum(int p)
{
int ans=0;
for (int i=p;i;i-=lowbit(i)) ans^=s[i];
return ans;
}
signed main()
{
n=read();int x,y;
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<n;i++)
x=read(),y=read(),adde(x,y);
dfs(1,0);
for (int i=1;i<=n;i++)
add(in[i],a[i]),add(out[i]+1,a[i]);
m=read();
while (m--)
{
char ch[5];scanf("%s",ch);
if (ch[0]=='Q')
{
int x=read(),y=read(),l=lca(x,y);
int ans=sum(in[x])^sum(in[y])^a[l];
ans?puts("Yes"):puts("No");
}
else
{
int x=read(),y=read();
add(in[x],a[x]);add(out[x]+1,a[x]);
a[x]=y;
add(in[x],a[x]);add(out[x]+1,a[x]);
}
}
return 0;
}