• BZOJ3729 Gty的游戏


    转一发blog

    首先看这道题的博弈部分,也就是如何得到答案。对于单个节点来说,这就是一个简单的巴什博弈问题,每次可以拿走[1..L]个的话,只需要把石子个数对L+1取模就可以得到它的SG值了。如果考虑树上操作这就是一个阶梯博弈,每次只需要考虑奇数层上的石子。那么只需要对每棵子树维护它的奇数层SG值和偶数层SG值就可以了。因为有插入节点的操作所以dfs序要用Splay来维护。

    这道题里面最关键的操作是插入节点的操作。因为访问子树的时候要知道它的入栈点和出栈点,也就是in和out,而如果插入了一个节点就有可能引起很多节点out值的变化。

    一个节点的in显然就是它自己,但out值是它子树里最后一个被遍历的节点,也就是它一定是一个叶子节点。那么如果在某个叶子节点下面接了一个节点,就有至少一个节点的out会变化。而我们可以发现这个寻找out的关系是具有传递性的,比如树上某个节点x把u当做它的out,而u当前的out节点指向新接入的儿子v,那么x的out也应该指向v。这就启示我们可以用并查集来维护这个东西,把每个节点并到它的out上去就可以了。

    而为了让修改out的次数尽量少,如果接入新节点的那个父亲不是叶子节点,我们可以通过适当处理让所有节点的out都不变,方法就是把新节点的dfs序紧挨着父节点放在它后面。比如当前有dfs序:u-v-w,v和w都是u的儿子,那么显然u的out是w。如果现在还要给u接一个新儿子x,那么我们可以把dfs序修改成:u-x-v-w,这样的话所有已有节点的in和out都不会变。而如果修改成:u-v-w-x,u的out就变了,就造成了不必要的修改。

    http://blog.csdn.net/fromatp/article/details/54800000

    我们先来看一道POJ1704阶梯博弈题,做法就是将偶的并在一起,奇的话就将1和0并在一起,变成nim博弈。

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int a[1005],n,T;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);int sum=0;
            for(int i=1;i<=n;++i)scanf("%d",&a[i]);
            sort(a+1,a+1+n);
            for(int i=(n&1)^1;i<=n;i+=2)
            sum=sum^(a[i+1]-a[i]-1);
            if(sum==0)puts("Bob will win");
            else puts("Georgia will win");
        }
    }

    然后是本题代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+10;
    int val[N],fa[N],c[N][2],sg[N][2],typ[N],a[N],dep[N],pos[N][2],st[N];
    int n,mod,rt,num,tot,m,head[N],ccnt;
    map<int,int>id;
    struct node
    {
        int to,nex;
    }e[N];
    void add(int x,int y)
    {
        e[++ccnt].to=y;e[ccnt].nex=head[x];head[x]=ccnt;
    }
    void update(int x)
    {
        sg[x][0]=sg[c[x][0]][0]^sg[c[x][1]][0];
        sg[x][1]=sg[c[x][0]][1]^sg[c[x][1]][1];
        sg[x][typ[x]]=sg[x][typ[x]]^val[x];
    }
    void rotate(int x,int &k)
    {
        int y=fa[x],z=fa[y],l,r;
        if(c[y][0]==x)l=0;else l=1;r=l^1;
        if(y==k)k=x;
        else {if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
        c[y][l]=c[x][r];c[x][r]=y;
        update(y);update(x);
    }
    void splay(int x,int &k)
    {
        while(x!=k)
        {
            int y=fa[x],z=fa[y];
            if(y!=k)
            {
                if(c[y][0]==x^c[z][0]==y)rotate(x,k);
                else rotate(y,k);
            }
            rotate(x,k);
        }
    }
    void query(int x)
    {
        splay(pos[x][0],rt);
        splay(pos[x][1],c[rt][1]);
        if(sg[c[pos[x][1]][0]][dep[x]^1])
        {
            num++;puts("MeiZ");
        }
        else puts("GTY");
    }
    void build(int l,int r,int f)
    {
        if(l>r)return;
        int mid=l+r>>1;
        c[f][mid>=f]=mid;fa[mid]=f;
        pos[abs(st[mid])][st[mid]<0]=mid;
        if(st[mid]>0)val[mid]=a[st[mid]];
        typ[mid]=dep[abs(st[mid])];
        build(l,mid-1,mid);build(mid+1,r,mid);
        update(mid);
    }
    void dfs(int x)
    {
        st[++tot]=x;
        for(int i=head[x];i;i=e[i].nex)
        {
            int y=e[i].to;
            dep[y]=dep[x]^1;
            dfs(y);
        }
        st[++tot]=-x;
    }
    void insert(int x,int y,int w)
    {
        splay(pos[x][0],rt);
        int k=c[rt][1];while(c[k][0])k=c[k][0];
        int t1=++tot,t2=++tot;
        pos[y][0]=t1;pos[y][1]=t2;fa[t1]=k;fa[t2]=t1;
        dep[y]=dep[x]^1;c[k][0]=t1;c[t1][1]=t2;val[t1]=w;
        typ[t1]=typ[t2]=dep[y];
        update(t2);update(t1);update(k);splay(t2,rt);
    }
    int main()
    {
        scanf("%d%d",&n,&mod);mod++;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);a[i]%=mod;
            id[i]=i;
        }
        int x,y,f,z;
        for(int i=1;i<n;++i)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        dfs(1);build(1,tot,0);rt=1+tot>>1;
        scanf("%d",&m);
        for(int i=1;i<=m;++i)
        {
            scanf("%d",&f);
            if(f==1){
                scanf("%d",&x);x=x^num;
                query(id[x]);
            }
            else if(f==2){
                scanf("%d%d",&x,&y);x^=num;y^=num;y%=mod;
                splay(pos[id[x]][0],rt);val[rt]=y;update(rt);
            }
            else{
                scanf("%d%d%d",&x,&y,&z);
                x^=num;y^=num;z^=num;z%=mod;id[y]=++n;
                insert(id[x],n,z);
            }
        }
        return 0;
    }
  • 相关阅读:
    RDD的五个属性
    惰性求值的概念
    大数据shuffle的理解
    简单说明hadoop和hbase的异同
    Linux 下命令有哪几种可使用的通配符?分别代表什么含义?
    linux命令知识点复习
    >/dev/null 2>&1
    JAVA内存泄漏和内存溢出的区别和联系
    Linux各个目录的作用
    JVM标准参数-server与-client参数的区别
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8297547.html
Copyright © 2020-2023  润新知