题目:http://acm.hdu.edu.cn/showproblem.php?pid=5274
在树上的询问和操作,每次修改单点值,询问两点之间出现次数为奇数的点权是什么,若没有输出-1.询问保证两点间至多只有一个数出现奇数次。有一种经典的将树上的点转化成序列的方法,我们用dfs遍历这棵树,那么对于一个节点,他一点比他的子树即子节点先访问到,且当他的最后一个子节点的所有子树也都访问完时,这中间访问的节点一定都是他的子树。那么我们可以在访问时做一下记录,每个点首先被访问的clock,和结束时的clock,那么这中间的便是他的子树。
剩下的就可以用线段树维护区间异或和了。
这题有坑的地方就是点权可能为0,处理方法是先把所以的点权都加上1,最后再减1.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#define Lson Ls,L,mid
#define Rson Rs,mid+1,R
using namespace std;
typedef long long ll;
const int N = 2*1e5+10;
const int maxh = 20;
vector<int> g[N];
int anc[N][maxh];
int n,q,u,v,clock;
int st[N],ed[N],deep[N];
int val[N];
void dfs(int x,int pa,int de){
deep[x] = de;
st[x] = ++clock;
anc[x][0] = pa;
for(int i=0;i<g[x].size();i++)if(g[x][i]!=pa){
dfs(g[x][i],x,de+1);
}
ed[x] = clock;
}
void init_lca(){
dfs(1,-1,0);
for(int k=0;k<maxh-1;k++){
for(int i=1;i<=n;i++)
if(anc[i][k]<0) anc[i][k+1] = -1;
else anc[i][k+1] = anc[anc[i][k]][k];
}
}
int swim(int x, int H){
for(int i = 0; H; i++){
if (H&1) x = anc[x][i];
H >>= 1;
}
return x;
}
int lca(int u,int v){
if(deep[u]>deep[v]) swap(u,v);
int H = deep[v]-deep[u];
v = swim(v,H);
if(u==v) return u;
for(int k=maxh-1;k>=0;k--)
if(anc[u][k]!=anc[v][k]){
u = anc[u][k];
v = anc[v][k];
}
return anc[u][0];
}
struct Node{
int val, set;
}tree[N<<2];
inline void update(Node& fa, Node& Ls, Node& Rs){
fa.val = (Ls.val ^ Rs.val);
}
inline void pushdown(Node& fa, Node& Ls, Node& Rs){
if (fa.set != 0){
Ls.val ^= fa.set; Ls.set ^= fa.set;
Rs.val ^= fa.set; Rs.set ^= fa.set;
fa.set = 0;
}
}
void insert(int v, int L, int R, int p, int q, int delta){
if (p<=L && R<=q){
tree[v].val ^= delta;
tree[v].set ^= delta;
return;
}
int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
pushdown(tree[v], tree[Ls], tree[Rs]);
if (q<=mid) insert(Lson, p, q, delta);
else if (p>mid) insert(Rson, p, q, delta);
else{
insert(Lson, p, q, delta);
insert(Rson, p, q, delta);
}
update(tree[v], tree[Ls], tree[Rs]);
}
int query(int v, int L, int R,int ql, int qr){
if(ql<=L && R<=qr){
return tree[v].val;
}
int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
pushdown(tree[v], tree[Ls], tree[Rs]);
int ans = 0;
if(qr<=mid) ans ^= query(Lson,ql,qr);
else if(ql>mid) ans ^= query(Rson,ql,qr);
else{
ans ^= query(Lson,ql,qr);
ans ^= query(Rson,ql,qr);
}
return ans ;
}
int MAIN(){
int T;
cin >> T;
while(T--){
clock = 0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
val[i]++;
}
init_lca();
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
insert(1,1,n,st[i],ed[i],val[i]);
for(int i=1;i<=q;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a==0){
c++;
insert(1,1,n,st[b],ed[b],val[b]^c);
val[b] = c;
}
else{
int wt1 = query(1,1,n,st[b],st[b]);
int wt2 = query(1,1,n,st[c],st[c]);
int hc = lca(b,c);
int wt3 = val[hc];
int ans = wt1^wt2^wt3;
printf("%d\n",ans-1);
}
}
}
return 0;
}
const int main_stack = 16;
char my_stack[128<<20];
int main() {
__asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");
__asm__("movl %%eax, %%esp;\n"::"a"(my_stack + sizeof(my_stack) - main_stack):"%esp");
MAIN();
__asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");
return 0;
}