zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    BZOJ 3631 链剖+差分
    BZOJ 1103 DFS序+线段树
    BZOJ 3629 约数和定理+搜索
    198. House Robber
    152. Maximum Product Subarray
    139. Word Break
    132. Palindrome Partitioning II
    120. Triangle
    115. Distinct Subsequences
    97. Interleaving String
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2819.html
Copyright © 2011-2022 走看看