zoukankan      html  css  js  c++  java
  • [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
    ":"No
    ");
    		if (ch[0]=='C')	ST.Modify(1,1,n,ID[x],y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    如果使用Excel oledb 导数据出现各种错误的解决方法
    如何对给定序列进行趋势预测
    Winform自定义控件之二叉树控件(2)
    WinForm自定义控件开发(1)
    .net 3.5 中的 服务器端回调
    Python内存管理
    oracle to mysql hibernate 实体id生成策略配置
    oracle to mysql
    mysql 删除所有表
    oracle函数在mysql用
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9949205.html
Copyright © 2011-2022 走看看