洛谷 P5556 圣剑护符(线性基、树剖、线段树)
传送门
解题思路
关键点:根据线性基的性质,若序列数字个数大于等于30,则一定有异或值为0的两个集合。
所以对于每个询问,先判断两个点之间的路径长度是否大于等于30,若小于30,直接暴力找,线性基判断,否则直接判断。
对于每次修改,可以用线段树维护树剖。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
using namespace std;
const int maxn=1e5+5;
int p[maxn],n,q,cnt,siz[maxn],son[maxn],dfn[maxn],v[maxn],fa[maxn],dep[maxn],times,tp[maxn],vv[maxn];
int a[35];
int d[maxn*6],lazy[maxn*6];
struct node{
int v,next;
}e[maxn*2];
void insert(int u,int v){
cnt++;
e[cnt].v=v;
e[cnt].next=p[u];
p[u]=cnt;
}
void add(int x){
for(int i=29;i>=0;i--){
if(x&(1<<i)){
if(a[i]) x^=a[i];
else{
a[i]=x;
return;
}
}
}
}
bool check(int x){
for(int i=29;i>=0;i--){
if(x&(1<<i)){
if(a[i]) x^=a[i];
else return 1;
}
}
return 0;
}
void dfs1(int u,int f,int deep){
siz[u]=1;
fa[u]=f;
dep[u]=deep;
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(v==f) continue;
dfs1(v,u,deep+1);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int top){
dfn[u]=++times;
tp[u]=top;
if(son[u]) dfs2(son[u],top);
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int getlca(int x,int y){
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
x=fa[tp[x]];
}
return dep[x]<dep[y]?x:y;
}
void pushdown(int id){
if(lazy[id]){
d[id*2]^=lazy[id];
d[id*2+1]^=lazy[id];
lazy[id*2]^=lazy[id];
lazy[id*2+1]^=lazy[id];
lazy[id]=0;
}
}
void update(int id,int l,int r,int x,int y,int v){
if(x<=l&&r<=y){
d[id]^=v;
lazy[id]^=v;
return;
}
int mid=(l+r)/2;
pushdown(id);
if(x<=mid) update(id*2,l,mid,x,y,v);
if(y>mid) update(id*2+1,mid+1,r,x,y,v);
}
int query(int id,int l,int r,int x){
if(l==r){
return d[id];
}
int mid=(l+r)/2;
pushdown(id);
if(x<=mid) return query(id*2,l,mid,x);
return query(id*2+1,mid+1,r,x);
}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>vv[i];
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
insert(u,v);
insert(v,u);
}
dfs1(1,-1,1);
dfs2(1,1);
while(q--){
string s;
cin>>s;
if(s=="Query"){
int x,y;
cin>>x>>y;
int lca=getlca(x,y);
if(dep[x]+dep[y]-2*dep[lca]>=30) cout<<"YES"<<endl;
else{
int ok=0;
memset(a,0,sizeof(a));
while(ok==0&&x!=lca){
int val=query(1,1,n,dfn[x])^vv[x];
if(check(val)) add(val);
else{
cout<<"YES"<<endl;
ok=1;
}
x=fa[x];
}
while(ok==0&&y!=lca){
int val=query(1,1,n,dfn[y])^vv[y];
if(check(val)) add(val);
else{
cout<<"YES"<<endl;
ok=1;
}
y=fa[y];
}
if(ok) continue;
int val=query(1,1,n,dfn[lca])^vv[lca];
if(check(val))
cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
}else{
int x,y,z;
cin>>x>>y>>z;
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
update(1,1,n,dfn[tp[x]],dfn[x],z);
x=fa[tp[x]];
}
if(dep[x]<dep[y]) swap(x,y);
update(1,1,n,dfn[y],dfn[x],z);
}
}
return 0;
}