[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;
}
posted @ 2017-04-27 22:58  FallDream  阅读(179)  评论(0编辑  收藏  举报