題意
求帶單點修改的樹上兩點間任意子路徑長異或和。
路徑長等於路徑上所有異或和。
題解
簡單模擬一下,可以發現。
奇數情況下,答案是偶數點異或和。
偶數情況下,就是正常的異或和。
偶數點異或和也很容易處理。
分深度奇偶樹狀數組即可。
但是這是對於鏈的,不能直接序,需要剖分一下。
但是我不會,所以去學了一下。
簡單意思就是:
孩子結點的子樹最大的作爲重兒子。
每次優先跑重兒子,可以使得序中重鏈都是連續的。
利用這個特徵,我們在處理的時候,每次跳到鏈頭,最後不斷處理詢問即可。
這其中:樹鏈剖分的複雜度是
不過我還有兩點疑問:
爲什麼複雜度能保證,以及爲什麼跳的時候要先跳鏈頭深度大的或者序大的。
不過目前這不是重點,我就先鴿了(被迫先學了樹剖,最近明明在弄圖論)
單點更新,三個線段樹即可。
#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;
}