题意
求带单点修改的树上两点间任意子路径长异或和。
路径长等于路径上所有异或和。
题解
简单模拟一下,可以发现。
奇数情况下,答案是偶数点异或和。
偶数情况下,就是正常的异或和。
偶数点异或和也很容易处理。
分深度奇偶树状数组即可。
但是这是对于链的,不能直接
d
f
s
dfs
dfs序,需要剖分一下。
但是我不会,所以去学了一下。
简单意思就是:
孩子结点的子树最大的作为重儿子。
每次优先跑重儿子,可以使得
d
f
s
dfs
dfs序中重链都是连续的。
利用这个特征,我们在处理的时候,每次跳到链头,最后不断处理询问即可。
这其中:树链剖分的复杂度是
n
l
o
g
2
n
nlog^2n
nlog2n
不过我还有两点疑问:
为什么复杂度能保证,以及为什么跳的时候要先跳链头深度大的或者
d
f
s
dfs
dfs序大的。
不过目前这不是重点,我就先鸽了(被迫先学了树剖,最近明明在弄图论)
单点更新,三个线段树即可。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn = 2e5+100;
vector<int>G[maxn];
int sz[maxn],son[maxn],dep[maxn];
int dfn[maxn],top[maxn],fa[maxn];
int A[maxn],cnt,n,m;
//剖分
void dfs1(int u,int pre){
dep[u]=dep[pre]+1;
sz[u]=1,fa[u]=pre;
int s=0;
for(auto v:G[u]){
if(v==pre)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>s)son[u]=v,s=sz[v];
}
}
void dfs2(int u,int tr_top){
dfn[u]=++cnt;
top[u]=tr_top;
if(son[u])dfs2(son[u],tr_top);
for(auto v:G[u]){
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
//树状数组
int C[maxn][3];
int lowbit(int x){return (x&(-x));}
void change(int x,int d,int id){for(int i=x;i<=n;i+=lowbit(i))C[i][id]^=d;}
int query(int x,int id){if(x==0)return 0;int ret=0;for(int i=x;i;i-=lowbit(i))ret^=C[i][id];return ret;}
//树链剖分更新
void update(int x,int c){
int val=A[x]^c;
change(dfn[x],val,dep[x]%2);
change(dfn[x],val,2);
if(c)A[x]=c;
}
int query(int l,int r,int id){
int ans=0,now;
if(dep[l]%2!=dep[r]%2)now=2;
else now=(dep[l]%2)^1;
//cout<<id<<"?"<<endl;
while(top[l]!=top[r]){
if(dep[l]<dep[r])swap(l,r);
ans^=query(dfn[l],now)^query(dfn[top[l]]-1,now);
// cout<<dfn[l]<<" "<<dfn[top[l]]-1<<endl;
l=fa[top[l]];
}
// cout<<l<<" "<<r<<" "<<dep[l]%2<<" "<<dep[r]%2<<endl;
if(dfn[l]<=dfn[r])ans^=query(dfn[r],now)^query(dfn[l]-1,now);
else ans^=query(dfn[l],now)^query(dfn[r]-1,now);
//cout<<dfn[l]<<" "<<dfn[r]<<endl;
return ans;
}
int main(){
cin>>n>>m;
FOR(i,1,n)scanf("%d",&A[i]);
FOR(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0);
dfs2(1,1);
FOR(i,1,n){
// cout<<i<<" "<<fa[i]<<" "<<sz[i]<<" "<<son[i]<<" "<<dep[i]<<" "<<dfn[i]<<" "<<top[i]<<endl;
}
FOR(i,1,n)update(i,0);
FOR(i,1,m){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1)update(l,r);
else printf("%d\n",query(l,r,i));
}
//cout<<dfn[2]<<endl;
// cout<<query(dfn[2],2)-query(dfn[2]-1,2)<<endl;
}