考虑到异或两次就会相消
经过分析发现
- 如果路径的长度是奇数个点,那么等效于所有偶数次序的点被记录一次
- 如果路径长度是偶数个点,那么所有点都被计入一次
考虑到次序这个东西可以用深度相邻黑白染色来实现,我们把树拆成两份,黑色一份,白色一份
黑色树上只记录黑色点的权值,白色点权值全部为零,白色树反之
偷懒直接上树链剖分,最后记得处理一下 LCA 上的答案
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
vector <int> g[N];
int n,m,a[N],t1,t2,t3;
int fa[N],siz[N],f[N],dep[N],wson[N],dfn[N],top[N],ind,tot;
void dfs1(int p) {
siz[p]=1;
for(int q:g[p]) {
if(q==fa[p]) continue;
fa[q]=p;
dep[q]=dep[p]+1;
dfs1(q);
siz[p]+=siz[q];
if(siz[q]>siz[wson[p]]) wson[p]=q;
}
}
void dfs2(int p) {
dfn[p]=++ind;
if(wson[p]) {
top[wson[p]]=top[p];
dfs2(wson[p]);
}
for(int q:g[p]) {
if(q==fa[p]) continue;
if(q==wson[p]) continue;
top[q]=q;
dfs2(q);
}
}
struct tree {
int a[1000005];
void modify(int p,int l,int r,int pos,int key) {
if(l==r) a[p]=key;
else {
if(pos<=(l+r)/2) modify(p*2,l,(l+r)/2,pos,key);
else modify(p*2+1,(l+r)/2+1,r,pos,key);
a[p]=a[p*2]^a[p*2+1];
}
}
int query(int p,int l,int r,int ql,int qr) {
if(l>qr || r<ql) return 0;
if(l>=ql&&r<=qr) return a[p];
return query(p*2,l,(l+r)/2,ql,qr)^query(p*2+1,(l+r)/2+1,r,ql,qr);
}
int lca(int x,int y) {
for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
return dep[x]<dep[y]?x:y;
}
int dist(int x,int y) {
int l=lca(x,y);
return dep[x]+dep[y]-2*dep[l];
}
void tmodify(int p,int key) {
modify(1,1,n,dfn[p],key);
}
int lquery(int p) {
int ans=0;
while(p) {
int t=top[p];
ans^=query(1,1,n,dfn[t],dfn[p]);
p=fa[t];
}
return ans;
}
int tquery(int p,int q) {
int l=lca(p,q);
int ans=query(1,1,n,dfn[l],dfn[l]);
ans^=lquery(p);
ans^=lquery(q);
return ans;
}
} A,B;
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>a[i];
}
for(int i=1;i<n;i++) {
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
dep[1]=1;
dfs1(1);
top[1]=1;
dfs2(1);
for(int i=1;i<=n;i++) {
if(dep[i]&1) A.tmodify(i,a[i]);
else B.tmodify(i,a[i]);
}
for(int i=1;i<=m;i++) {
cin>>t1>>t2>>t3;
if(t1==1) {
a[t2]=t3;
if(dep[t2]&1) A.tmodify(t2,a[t2]);
else B.tmodify(t2,a[t2]);
}
else {
int d=A.dist(t2,t3);
if(d%2==0) {
if(dep[t2]&1) {
cout<<B.tquery(t2,t3)<<endl;
}
else {
cout<<A.tquery(t2,t3)<<endl;
}
}
else {
cout<<(A.tquery(t2,t3)^B.tquery(t2,t3))<<endl;
}
}
}
}