#194-[树链剖分,博弈论] Nim游戏

Description

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

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


 

Input

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

Output

对于每个Q,输出一行YesNo,代表对询问的回答。

 

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 Input

Yes
No
Yes
Yes
Yes
  • Sample Output

HINT

对于30%的数据,1≤N≤1001≤Q≤100
对于100%的数据,1≤N≤500000 1≤Q≤500000 0≤任何时候每堆石子的个数max longint
其中有30%的数据,石子堆组成了一条链

注意:石子数的范围是0max longint

 

Source/Category

树链剖分 

一眼看——树链剖分

再一看——博弈论?毒瘤?

如果所有数异或到一起不为0,先手就有必胜策略。

(并不知道原理)

#include 
#include 
#include 

using namespace std;

const int SIZE = 500010;

vector ved[SIZE];
int n, a[SIZE], dp[SIZE<<2], father[SIZE], depth[SIZE], tsize[SIZE], son[SIZE], dfn[SIZE], revdfn[SIZE], top[SIZE], dfstime;

/* 维护线段树 */

void buildtree(int rt, int l, int r) { // 建树
	if (l==r) {
		dp[rt] = a[revdfn[l]]; return;
	}
	int m = (l+r) >> 1; buildtree(rt<<1, l, m); buildtree(rt<<1|1, m+1, r);
	dp[rt] = dp[rt<<1] ^ dp[rt<<1|1];
	
	return;
}

void update(int rt, int l, int r, int x, int val) { // 更新(没有懒标记,舒服)
	if (l==r) {
		dp[rt] = val; return;
	}
	int m = (l+r) >> 1; if (x<=m) update(rt<<1, l, m, x, val); else update(rt<<1|1, m + 1, r, x, val);
	dp[rt] = dp[rt<<1] ^ dp[rt<<1|1];
	
	return;
}

int query(int rt, int l, int r, int x, int y) { // 查询区间
	if ((x<=l) && (r<=y)) return dp[rt];
	int m = (l+r) >> 1, res = 0; if (x<=m) res ^= query(rt<<1, l, m, x, y); if (y>m) res ^= query(rt<<1|1, m+1, r, x, y);
	
	return res;
}

/* 树链剖分 */

void dfs(int u, int fa, int dep) { // 第一次深搜,重儿子深度大小
	father[u] = fa; depth[u] = dep; tsize[u] = 1; son[u] = 0;
	for (unsigned int i=0; idepth[y]) swap(x, y);
	
	return res ^ query(1, 1, n, dfn[x], dfn[y]);
}

int main(void) {	
	scanf("%d", &n);
	for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
	for (int i=1; i

 

你可能感兴趣的:(刷题,gdgzoi刷题)