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;
}

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/9949205.html
Nim