题目链接:Tree
题意:一棵树,有点权,支持链上所有点与一个数字,或一个数字,询问链上所有点异或和异或题目给定的数字是否为正数。
树链剖分将链转换为区间。
先考虑线段树的操作,将点权拆解成二进制,那么区间与,或就相当于区间覆盖0,1,线段树维护区间内每一位的1的个数。
对于操作1,2直接做。
对于查询3,可以做30次查询,每次查询链上所有数字这一位上1的个数是否为奇数,再加上给出数字这一位上1的个数,如果是奇数说明答案一定是正数。
复杂度为 O ( q ∗ 30 ∗ l o g 2 n ∗ l o g 2 n ) O(q*30*log_2n*log_2n) O(q∗30∗log2n∗log2n)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
struct Edge{
int v,next;
}edge[maxn<<1];
int head[maxn],top;
void init(){
top=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v){
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
int dep[maxn],val[maxn],fa[maxn],dfn[maxn],num,size1[maxn],son[maxn],topp[maxn],W[maxn];
bool vis[maxn];
void dfs1(int u){
vis[u]=1;
size1[u]=1;
int v;
int maxx=-1;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(vis[v]) continue;
dep[v]=dep[u]+1;
fa[v]=u;
dfs1(v);
size1[u]+=size1[v];
if(size1[v]>maxx){
son[u]=v;
maxx=size1[v];
}
}
}
void dfs2(int u,int last){
topp[u]=last;
dfn[u]=++num;
val[num]=W[u];
if(!son[u]) return ;
dfs2(son[u],last);
int v;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(dfn[v]||v==son[u]) continue;
dfs2(v,v);
}
}
int sum[maxn<<2|1][34];
int lazy[maxn<<2|1][34];
const int ci=30;
void pushup(int k){
for(int i=0;i<=ci;++i)
sum[k][i]=sum[k<<1][i]+sum[k<<1|1][i];
}
void pushdown(int l,int r,int k){
int mid=(l+r)>>1;
for(int i=0;i<=30;++i)
if(lazy[k][i]!=-1){
lazy[k<<1][i]=lazy[k<<1|1][i]=1*lazy[k][i];
sum[k<<1][i]=(mid-l+1)*lazy[k][i];
sum[k<<1|1][i]=(r-mid)*lazy[k][i];
lazy[k][i]=-1;
}
}
void build(int l,int r,int k){
for(int i=0;i<=ci;++i) lazy[k][i]=-1;
if(l==r){
for(int i=0;i<=30;++i)
if(val[l]&(1<<i)) sum[k][i]=1;
else sum[k][i]=0;
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushup(k);
}
//1| 2&
void updata(int l,int r,int k,int L,int R,int type,int val){
if(l>=L&&r<=R){
if(type){
for(int i=0;i<=ci;++i)
if(val&(1<<i)) sum[k][i]=r-l+1,lazy[k][i]=1;
}
else{
for(int i=0;i<=ci;++i)
if(!(val&(1<<i))) sum[k][i]=0,lazy[k][i]=0;
}
return ;
}
int mid=(l+r)>>1;
pushdown(l,r,k);
if(L<=mid) updata(l,mid,k<<1,L,R,type,val);
if(R>mid) updata(mid+1,r,k<<1|1,L,R,type,val);
pushup(k);
}
int myfind(int l,int r,int k,int L,int R,int id){
int res=0;
if(l>=L&&r<=R){
return sum[k][id];
}
pushdown(l,r,k);
int mid=(l+r)>>1;
if(L<=mid) res+=myfind(l,mid,k<<1,L,R,id);
if(R>mid) res+=myfind(mid+1,r,k<<1|1,L,R,id);
pushup(k);
return res;
}
int n;
void updatachain(int x,int y,int type,int val){
while(topp[x]!=topp[y]){
if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
updata(1,n,1,dfn[topp[x]],dfn[x],type,val);
x=fa[topp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
updata(1,n,1,dfn[x],dfn[y],type,val);
}
int myfindchain(int x,int y,int id){
int res=0;
while(topp[x]!=topp[y]){
if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
res+=myfind(1,n,1,dfn[topp[x]],dfn[x],id);
x=fa[topp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
res+=myfind(1,n,1,dfn[x],dfn[y],id);
return res;
}
bool op3(int x,int y,int t){
int res=0;
for(int i=0;i<=30;++i){
if(t&(1<<i)) res=1;
else res=0;
res+=myfindchain(x,y,i);
if(res&1) return 1;
}
return 0;
}
int main(){
//cout<<(int)(maxn*pow(log2(maxn),3))<<endl;
init();
int q,u,v,id;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) scanf("%d",&W[i]);
for(int i=1;i<n;++i){
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,1);
build(1,n,1);
while(q--){
scanf("%d%d%d",&id,&u,&v);
if(id==1){
updatachain(1,u,1,v);
}
else if(id==2){
updatachain(1,u,0,v);
}
else{
printf("%s\n",(op3(1,u,v)?"YES":"NO"));
}
}
return 0;
}