• 2019.01.06-dtoj-3729: Gty的游戏


    题目描述:

    某一天gty在与他的妹子玩游戏。妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问
    将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
    gty很快计算出了策略。
    但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
    gty不忍心打击妹子,所以他将这个问题交给了你。
    另外由于gty十分绅士,所以他将先手让给了妹子。

    输入:

    第一行两个数字,n和L,n<=5*10^4,L<=10^9
    第二行n个数字,表示每个节点初始石子数。
    接下来n-1行,每行两个整数u和v,表示有一条从u到v的边。
    接下来一行一个数m,表示m组操作。
    接下来m行,每行第一个数字表示操作类型
    若为1,后跟一个数字v,表示询问在v的子树中做游戏先手是否必胜。
    若为2,后跟两个数字x,y表示将节点x的石子数修改为y。
    若为3,后跟三个数字u,v,x,表示为u节点添加一个儿子v,初始石子数为x。
    在任意时刻,节点数不超过5*10^4。

    算法标签:splay,博弈

    思路:

    首先,对于把石子移到子树的根的问题其实是一个阶梯nim问题,倘若把奇数层的节点异或后值为0,则先手必败,其余必胜。

    对于修改操作,用splay维护,在splay中子树的范围确定,从我向后找到第一个深度小于我的点之前的点都是我的子树,其余的都比较好维护。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5;
    int head[N],ne[N<<1],to[N<<1],tot,rt;
    int n,l,a[N],mnd[N],m,cnt,sum[N][2],d[N],num[N],son[N][2],sz[N],last,fa[N];
    il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
    il void insert(int x,int y){ne[++tot]=head[x];head[x]=tot;to[tot]=y;}
    il void dfs(int x,int fa){
        num[++cnt]=x;
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i])continue;
            d[to[i]]=d[x]+1;dfs(to[i],x);
        }
    }
    il void update(int x){
        sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;
        sum[x][1]=sum[son[x][1]][1]^sum[son[x][0]][1];
        sum[x][0]=sum[son[x][1]][0]^sum[son[x][0]][0];
        sum[x][d[x]&1]^=a[x];mnd[x]=d[x];
        if(son[x][0])mnd[x]=min(mnd[x],mnd[son[x][0]]);
        if(son[x][1])mnd[x]=min(mnd[x],mnd[son[x][1]]);
    }
    il void build(int &x,int l,int r,int now){
        
        int mid=(l+r)>>1;x=num[mid];fa[x]=now;
        if(l<mid)build(son[x][0],l,mid-1,x);
        if(mid<r)build(son[x][1],mid+1,r,x);
        update(x);
    }
    il void rotate(int x,int &k){
        int y=fa[x],z=fa[y],tp=son[y][1]==x;
        if(y==k)k=x;else son[z][son[z][1]==y]=x;
        
        son[y][tp]=son[x][tp^1];fa[son[y][tp]]=y;
        son[x][tp^1]=y;fa[y]=x;fa[x]=z;
        update(y);update(x);
        
    }
    il void splay(int x,int&k){
        while(x!=k){
            int y=fa[x],z=fa[y];
            if(y!=k)rotate(((son[y][1]==x^son[z][1]==y)?x:y),k);
            rotate(x,k);
        }
    }
    il int find(int x,int k){
        if(!x)return 0;
        if(min(mnd[son[x][0]],d[x])>k)return find(son[x][1],k);
        if(mnd[son[x][0]]>k)return x;
        return find(son[x][0],k);
    }
    int main()
    {
        n=read();l=read();mnd[0]=1e9;
        for(int i=1;i<=n;i++)a[i]=read()%(l+1);
        for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}
        d[1]=1;num[++cnt]=1e5+1;dfs(1,0);num[++cnt]=1e5+2;
        build(rt,1,cnt,0);
        m=read();
        while(m--){
            int op=read();
            if(op==1){
                int x=read()^last;
                splay(x,rt);
                int y=find(son[x][1],d[x]);
                splay(y,son[x][1]);
                int res=sum[son[y][0]][(d[x]&1)==0];
                if(!son[y][0]||!res)puts("No");
                else puts("Yes"),++last;
            }
            else if(op==2){
                int x=read()^last;a[x]=(read()^last)%(l+1);
                for(;x;x=fa[x])update(x);
            }
            else{
                int x=read()^last,z=read()^last,y;
                splay(x,rt);y=son[x][1];while(son[y][0])y=son[y][0];
                a[z]=(read()^last)%(l+1),d[z]=d[x]+1;
                if(!y)fa[z]=x,son[x][1]=z,update(z),update(x);
                else{
                    splay(y,son[x][1]);son[y][0]=z;fa[z]=y;
                    update(z);update(y);update(x);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    线程池小结(一)
    [转]ViewPager学习笔记(一)——懒加载
    [转]Private Libraries、Referenced Libraries、Dependency Libraries的区别
    关于context你必须知道的一切
    【转】在mac上配置安卓SDK
    【转】HTTP中的长连接和短连接分析
    中间件解析FDMEMTABLE.delta生成SQL的方法
    delphi 中配置文件的使用(*.ini)和TIniFile 用法
    Delphi 字符串加密与解密函数
    Delphi编写的等长加密与解密
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10230737.html
Copyright © 2020-2023  润新知