题意
- 给定一棵树,并给定在这棵树上的两种操作。一种操作是改变一个节点的权值,另外一个操作是对两个节点之间的路径上的权值进行统计,如果每个权值出现的次数都是偶数,输出-1,否则输出出现次数为奇数的权值(保证只有一个)
思路
- 这题是一个DFS序的模板题。首先想到,我们获得这棵树的DFS序,对于这个序列,我们可以去维护区间的异或和。由于是单点修改区间查询,可以用树状数组也可以直接写线段树。然后对于每个询问,我们查询出每个点到根的异或和(这里直接用DFS序中到根节点的异或和即可,因为如果一个结点不在其到根节点的路径上,其会出现两次,异或和为0),然后求出这两个结点的LCA,再异或LCA的权值。注意这个地方,如果一个结点权值为0,会出错。所以这里要进行处理(把权值都加1,输出答案的时候减1)。LCA用倍增法、Tarjan、RMQ都可以。
- 这题HDU略坑,交G++一直爆栈。然而没必要去管这个。。交C++就过了。
AC代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = 110000;
int cnt,head[MAXN],dep[MAXN],p[MAXN][20],tot;
int st[MAXN],ed[MAXN];
int sum[MAXN<<3];
int n,q;
void update(int pos,int c,int l,int r,int rt){
if(l == r){
sum[rt] = c;
return;
}
int m = (l+r)>>1;
if(pos <= m)update(pos,c,lson);
else update(pos,c,rson);
sum[rt] = sum[rt<<1] ^ sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt){
if(l>=L && R>=r){
return sum[rt];
}
int ret = 0;
int m = (l+r)>>1;
if(L <= m)ret ^= query(L,R,lson);
if(R > m)ret ^= query(L,R,rson);
return ret;
}
struct Edge{
int u,v;
int next;
}e[MAXN<<1];
void addedge(int u,int v){
e[cnt].u = u,e[cnt].v = v,e[cnt].next = head[u],head[u] = cnt++;
e[cnt].u = v,e[cnt].v = u,e[cnt].next = head[v],head[v] = cnt++;
}
void dfs(int u){
st[u] = tot++;
for(int i=head[u];i!=-1;i=e[i].next){
int v = e[i].v;
if(!dep[v]){
dep[v] = dep[u] + 1;
p[v][0] = u;
dfs(v);
}
}
ed[u] = tot++;
}
void init(){
cnt = 0;
tot = 1;
memset(head,-1,sizeof(head));
memset(p,-1,sizeof(p));
memset(dep,0,sizeof(dep));
}
int LCA(int a,int b){
if(dep[a]<dep[b])swap(a,b);
int i;
for(i = 0;(1<<i)<=dep[a];i++);
i--;
for(int j=i;j>=0;j--)
if(dep[a]-(1<<j)>=dep[b])
a = p[a][j];
if(a == b)return a;
for(int j=i;j>=0;j--){
if(p[a][j]!=-1 && p[a][j] != p[b][j]){
a = p[a][j];
b = p[b][j];
}
}
return p[a][0];
}
int u,v;
int main()
{
int T;
cin>>T;
while(T--){
scanf("%d%d",&n,&q);
init();
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
}
dep[1] = 1;
dfs(1);
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
if(p[i][j-1] != -1)
p[i][j] = p[p[i][j-1]][j-1];
tot--;
memset(sum,0,sizeof(sum));
//for(int i=1;i<=n;i++)printf("%d ",st[i]);
//printf("tot : %d\n",tot);
for(int i=1;i<=n;i++){
scanf("%d",&u);
update(st[i],u+1,1,tot,1),update(ed[i],u+1,1,tot,1);
}
while(q--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op == 0){
update(st[x],y+1,1,tot,1),update(ed[x],y+1,1,tot,1);
}else{
int ansx = query(1,st[x],1,tot,1),ansy = query(1,st[y],1,tot,1);
int lca = LCA(x,y),anslca =query(st[lca],st[lca],1,tot,1);
//printf("ansx:%d ansy:%d lca:%d\n",ansx,ansy,lca);
int ans = ansx ^ ansy ^ anslca;
if( ans == 0)puts("-1");
else printf("%d\n",ans-1);
}
}
}
return 0;
}
时间: 2024-10-20 13:02:46