[BZOJ2819]Nim

Description
著名游戏设计师vfleaking,最近迷上了Nim。普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取。谁不能取谁输。这个游戏是有必胜策略的。于是vfleaking决定写一个玩Nim游戏的平台来坑玩家。
为了设计漂亮一点的初始局面,vfleaking用以下方式来找灵感:拿出很多石子,把它们聚成一堆一堆的,对每一堆编号1,2,3,4,...n,在堆与堆间连边,没有自环与重边,从任意堆到任意堆都只有唯一一条路径可到达。然后他不停地进行如下操作:

1.随机选两个堆v,u,询问若在v到u间的路径上的石子堆中玩Nim游戏,是否有必胜策略,如果有,vfleaking将会考虑将这些石子堆作为初始局面之一,用来坑玩家。
2.把堆v中的石子数变为k。

由于vfleaking太懒了,他懒得自己动手了。请写个程序帮帮他吧。

Input
第一行一个数n,表示有多少堆石子。
接下来的一行,第i个数表示第i堆里有多少石子。
接下来n-1行,每行两个数v,u,代表v,u间有一条边直接相连。
接下来一个数q,代表操作的个数。
接下来q行,每行开始有一个字符:
如果是Q,那么后面有两个数v,u,询问若在v到u间的路径上的石子堆中玩Nim游戏,是否有必胜策略。
如果是C,那么后面有两个数v,k,代表把堆v中的石子数变为k。

对于100%的数据:
1≤N≤500000, 1≤Q≤500000, 0≤任何时候每堆石子的个数≤32767
其中有30%的数据:
石子堆组成了一条链,这3个点会导致你DFS时爆栈(也许你不用DFS?)。其它的数据DFS目测不会爆。

注意:石子数的范围是0到INT_MAX

Output
对于每个Q,输出一行Yes或No,代表对询问的回答。

Sample Input
5
1 3 5 2 5
1 5
3 5
2 5
1 4
6
Q 1 2
Q 3 5
C 3 7
Q 1 2
Q 2 4
Q 5 3

Sample Output
Yes
No
Yes
Yes
Yes


其实就是个树剖板子题。。。只要会博弈论知识就好。。。不会博弈论可以参考这篇博客

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1;char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)    putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=5e5;
int dfn[N+10],ID[N+10],v[N+10],n;
struct S1{
	#define ls (p<<1)
	#define rs (p<<1|1)
	int tree[(N<<2)+10];
	void build(int p,int l,int r){
		if (l==r){
			tree[p]=v[dfn[l]];
			return;
		}
		int mid=(l+r)>>1;
		build(ls,l,mid),build(rs,mid+1,r);
		tree[p]=tree[ls]^tree[rs];
	}
	void Modify(int p,int l,int r,int x,int v){
		if (l==r){
			tree[p]=v;
			return;
		}
		int mid=(l+r)>>1;
		if (x<=mid)	Modify(ls,l,mid,x,v);
		else	Modify(rs,mid+1,r,x,v);
		tree[p]=tree[ls]^tree[rs];
	}
	int Query(int p,int l,int r,int x,int y){
		if (x<=l&&r<=y)	return tree[p];
		int mid=(l+r)>>1,res=0;
		if (x<=mid)	res^=Query(ls,l,mid,x,y);
		if (y>mid)	res^=Query(rs,mid+1,r,x,y);
		return res;
	}
}ST;//Segment Tree;
struct S2{
	int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
	int top[N+10],Rem[N+10],size[N+10],deep[N+10],fa[N+10];
	void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
	void insert(int x,int y){join(x,y),join(y,x);}
	void dfs(int x){
		deep[x]=deep[fa[x]]+1,size[x]=1;
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==fa[x])	continue;
			fa[son]=x,dfs(son);
			size[x]+=size[son];
			if (size[Rem[x]]<size[son])	Rem[x]=son;
		}
	}
	void build(int x){
		if (!x)	return;
		top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
		dfn[ID[x]=++Time]=x;
		build(Rem[x]);
		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
			if (son==fa[x]||son==Rem[x])	continue;
			build(son);
		}
	}
	int solve(int x,int y){
		int res=0;
		while (top[x]!=top[y]){
			if (deep[top[x]]<deep[top[y]])	swap(x,y);
			res^=ST.Query(1,1,n,ID[top[x]],ID[x]);
			x=fa[top[x]];
		}
		if (deep[x]>deep[y])	swap(x,y);
		res^=ST.Query(1,1,n,ID[x],ID[y]);
		return res;
	}
}HLD;//Heavy Light Decomposition
int main(){
	n=read();
	for (int i=1;i<=n;i++)	v[i]=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read();
		HLD.insert(x,y);
	}
	HLD.dfs(1),HLD.build(1),ST.build(1,1,n);
	int m=read();
	for (int i=1;i<=m;i++){
		char ch[2];
		scanf("%s",ch);
		int x=read(),y=read();
		if (ch[0]=='Q')	printf(HLD.solve(x,y)?"Yes\n":"No\n");
		if (ch[0]=='C')	ST.Modify(1,1,n,ID[x],y);
	}
	return 0;
}
posted @ 2018-11-12 21:24  Wolfycz  阅读(239)  评论(0编辑  收藏  举报