Loading

P5556 【圣剑护符】

♗Wendigo♝ 在大约一周前10min用线性基爆切此题。蒟蒻初学线性基,想起此事,便来一试

如果不会线性基,那么我推荐神♗Wendigo♝的线性基讲解 提交日报了,但是管理员莫名鸽子

这题可以用线性基推出一个结论:如果一个元素未能成功插入线性基,那么必然存在两个不相等的子集,使得两个子集的属性值相同。

粗略证明一下:如果未能成功插入元素 \(x\) ,说明原本那些数中某个集合的异或值等于 \(x\) ,那么那个集合与 \(x\) 就是 \(2\) 个不相等且属性值相同的子集。

又由于线性基最多 \(\log S\) 个元素,所以如果两点间距离大于 \(30\) ,必然有元素不能成功插入,直接输出 YES

修改,可以树剖完弄个树状数组维护区间异或和单点查询,就好了。因为插入线性基只需要单点查询 好像比较显然,没啥别的好说了qwq

查询,刚刚距离大于 \(30\) 的情况说过了。如果小于 \(30\) 暴力跳就好了,毕竟 \(30\) 比较小。然后应用上面那个结论,看看是否有元素未成功插入。

所以这题难点就是用线性基发现那个性质,其余都比较显然,而且代码超好写的。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
#define rint register int
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return x*f;
}
const int N=100010;
int n,q,v[N];
struct edge {
	int to,nxt;
}e[N<<1];
int head[N],num_edge;
int top[N],fa[N],dfn[N],timer,dep[N],siz[N],son[N];
bool can;
int d[40];
namespace BIT {
	int tr[N];
	#define lt(i) (i&(-i))
	void add(int x,int d) {for(rint i=x;i<=n;i+=lt(i))tr[i]^=d;}
	void upd(int l,int r,int d){add(l,d),add(r+1,d);}
	int ask(int x) {
		int res=0;
		for(rint i=x;i>0;i-=lt(i))res^=tr[i];
		return res;
	}
}
void addedge(int from,int to) {
	++num_edge;
	e[num_edge].nxt=head[from];
	e[num_edge].to=to;
	head[from]=num_edge;
}
void dfs1(int u,int ft) {
	siz[u]=1;
	for(rint i=head[u];i;i=e[i].nxt) {
		int v=e[i].to;
		if(v==ft)continue;
		dep[v]=dep[u]+1;
		fa[v]=u;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs2(int u,int tp)  {
	top[u]=tp;
	dfn[u]=++timer;
	if(son[u])dfs2(son[u],tp);
	for(rint i=head[u];i;i=e[i].nxt) {
		int v=e[i].to;
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}
int LCA(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
void update(int x,int y,int z) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
		BIT::upd(dfn[top[x]],dfn[x],z);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])x^=y^=x^=y;
	BIT::upd(dfn[x],dfn[y],z);
}
void clear() {
	can=0;
	for(rint i=0;i<=30;++i)d[i]=0;
}
void add(int x) {
	bool flg=1;
	for(rint i=30;~i;--i)
		if(x&(1<<i)) {
			if(d[i])x^=d[i];
			else {d[i]=x,flg=0;break;}
		}
	can|=flg;
}
bool query(int x,int y) {
	int lca=LCA(x,y);
	if(dep[x]+dep[y]-(dep[lca]<<1)>30)return 1;
	clear();
	while(dep[x]>dep[lca])add(v[x]^BIT::ask(dfn[x])),x=fa[x];
	while(dep[y]>dep[lca])add(v[y]^BIT::ask(dfn[y])),y=fa[y];
	add(v[lca]^BIT::ask(dfn[lca]));
	return can;
}
signed main() {
	n=rd(),q=rd();
	for(rint i=1;i<=n;++i)v[i]=rd();
	for(rint i=1,x,y;i<n;++i)
		x=rd(),y=rd(),addedge(x,y),addedge(y,x);
	dep[1]=1,dfs1(1,0),dfs2(1,1);
	char opt[10];
	while(q--) {
		scanf("%s",opt);int x=rd(),y=rd();
		if(opt[0]=='Q')puts(query(x,y)?"YES":"NO");
		else update(x,y,rd());
	} 
	return 0;
}
posted @ 2020-05-19 18:01  zzctommy  阅读(197)  评论(0编辑  收藏  举报