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;
}
路漫漫其修远兮,吾将上下而求索