题目链接:http://usaco.org/index.php?page=viewproblem2&cpid=921
题意:
给你一棵树,树上的每个结点都有一个权值。现在给你两种操作,一个是1 a b,表示将结点a的权值改成b,另一个是2 u v,表示查询从结点u到v路径上(包括u和v)所有点权值的异或和。
做法:
第一次用括号线段树做出来题目,心里有点激动。
括号线段树不想解释,解释起来一大堆。概括一下就是在搜索的时候,进入一个节点的时候标记一个点,出来的时候标记一个点,在这次的线段树上,这些点都要被附上这个点的值,有什么好处呢?因为我们的线段树记录的是异或和,所以如果当前这个点不是在我们想要的路径上,那么肯定会要么不进入,那么进入又再次出来了,异或一下就没有值了。更新的话也只需要修改单点即可,查询a到b的路径点权异或和的时候,只要找从根节点到a的值和根节点到b的值进行异或,由于他们的lca会被异或两次所以再把lca的值异或一下就可以了。
另外,emmm ,由于我们的oj会在深搜的时候爆栈..所以多加了一句话。
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int mod=(int)1e9+7;
const int maxn=100005;
int L[maxn],R[maxn],x[maxn];
int xsum[maxn*10],n,q,cnt,dep[maxn];
int P[maxn*2],fa[maxn][25];
vector<int> ve[maxn];
void dfs(int u,int f){
L[u]=++cnt;
P[cnt]=u;
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
if(v==f) continue;
dep[v]=dep[u]+1;
fa[v][0]=u;
dfs(v,u);
}
R[u]=++cnt;
P[cnt]=u;
}
void solve(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void build(int l,int r,int rt){
if(l==r){
xsum[rt]=x[P[l]];
return ;
}
int mid=(l+r)/2;
build(l,mid,lson);
build(mid+1,r,rson);
xsum[rt]=xsum[lson]^xsum[rson];
}
void update(int l,int r,int rt,int pos,int v){
if(l==r){
xsum[rt]=v;
return ;
}
int mid=(l+r)/2;
if(pos<=mid) update(l,mid,lson,pos,v);
else update(mid+1,r,rson,pos,v);
xsum[rt]=xsum[lson]^xsum[rson];
}
int query(int l,int r,int rt,int ql,int qr){
if(ql<=l&&r<=qr){
return xsum[rt];
}
int mid=(l+r)/2;
int ret=0;
if(ql<=mid) ret^=query(l,mid,lson,ql,qr);
if(qr>mid) ret^=query(mid+1,r,rson,ql,qr);
return ret;
}
int main(){
int size = 512 << 20; // 512MB
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p));
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&x[i]);
}
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
ve[x].push_back(y);
ve[y].push_back(x);
}
dep[1]=1;
dfs(1,-1);
build(1,cnt,1);
solve();
while(q--){
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(op==1){
x[a]=b;
update(1,cnt,1,L[a],b);
update(1,cnt,1,R[a],b);
}
else{
int lca=LCA(a,b);
int ans1=query(1,cnt,1,1,L[a]),ans2=query(1,cnt,1,1,L[b]);
printf("%d\n",ans1^ans2^x[lca]);
}
}
return 0;
}