[bzoj2819]Nim
来自FallDream的博客,未经允许,请勿转载,谢谢。
著名游戏设计师vfleaking,最近迷上了Nim。普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取。谁不能取谁输。这个游戏是有必胜策略的。于是vfleaking决定写一个玩Nim游戏的平台来坑玩家。
为了设计漂亮一点的初始局面,vfleaking用以下方式来找灵感:拿出很多石子,把它们聚成一堆一堆的,对每一堆编号1,2,3,4,...n,在堆与堆间连边,没有自环与重边,从任意堆到任意堆都只有唯一一条路径可到达。然后他不停地进行如下操作:
1.随机选两个堆v,u,询问若在v到u间的路径上的石子堆中玩Nim游戏,是否有必胜策略,如果有,vfleaking将会考虑将这些石子堆作为初始局面之一,用来坑玩家。
2.把堆v中的石子数变为k。
由于vfleaking太懒了,他懒得自己动手了。请写个程序帮帮他吧。
n,m<=500000
这道题其实就是在问你链上点的权值异或和是否为0
考虑求出dfs序之后用线段树维护每个点到根的路径的异或和,这样修改只要改一个区间就好了。
#include<iostream> #include<cstdio> #define MN 500000 #define MD 19 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,nl[MN+5],nr[MN+5],head[MN+5],dep[MN+5],p[MN+5],cnt=0,dn=0,S[MN+5],s[MN+5],fa[MD+1][MN+5]; struct edge{int to,next;}e[MN*2+5]; struct Tree{int l,r,x,val;}T[MN*4+5]; inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void build(int x,int l,int r) { if((T[x].l=l)==(T[x].r=r)){T[x].x=S[p[l]];return;} int mid=l+r>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); } void modify(int x,int l,int r,int v) { if(l==T[x].l&&T[x].r==r){T[x].x^=v;return;} int mid=T[x].l+T[x].r>>1; if(r<=mid) modify(x<<1,l,r,v); else if(l>mid) modify(x<<1|1,l,r,v); else modify(x<<1,l,mid,v),modify(x<<1|1,mid+1,r,v); } int query(int x,int k) { if(T[x].l==T[x].r) return T[x].x; int mid=T[x].l+T[x].r>>1; if(k<=mid) return query(x<<1,k)^T[x].x; else return query(x<<1|1,k)^T[x].x; } void dfs(int x) { p[nl[x]=++dn]=x; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa[0][x]) { fa[0][e[i].to]=x; S[e[i].to]^=S[x]; dep[e[i].to]=dep[x]+1; dfs(e[i].to); } nr[x]=dn; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j) if(k&1) x=fa[j][x]; if(x==y) return x; for(int i=MD;~i;--i) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y]; return fa[0][x]; } char op[5]; int main() { n=read(); for(int i=1;i<=n;i++) S[i]=s[i]=read(); for(int i=1;i<n;i++) ins(read(),read()); dfs(1);build(1,1,n); for(int i=1;i<=MD;i++) for(int j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]]; int q=read(); for(int i=1;i<=q;i++) { scanf("%s",op+1);int x=read(),y=read(); if(op[1]=='Q') { int L=lca(x,y); int ans=query(1,nl[x])^query(1,nl[y])^s[L]; puts(ans?"Yes":"No"); } else modify(1,nl[x],nr[x],s[x]^y),s[x]=y; } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream