洛谷 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;
}
上一篇:CF1045F Shady Lady【结论,计算几何】


下一篇:【TP5.1】中间件,定义全局中间件后,中间件别名会失效