BZOJ 3729: Gty的游戏

2 篇文章 0 订阅
1 篇文章 0 订阅

这两三天貌似没怎么写blog 来补点
劲啊 这道题 我的数据结构真心菜。。

首先对于子树来搞 显然就是用dfs序 由于动态加点 我们用splay

考虑博弈 距离这层为偶数层的可以不管 奇数层的就像简单NIM游戏一样取 当然了 每次只能取小于等于L的 直接MOD (L+1) 理由很简单 你取多少我都能筹够L+1和你抵消(orz 噶爷)*

所以就维护一下 奇偶数层的xor和
开点不用说了吧。。什么区间左端点作根右端点作右孩子

对了 这道题描述有点不对啊 最大那个数据 点数是超过了5*10^4的。。
所以你要开大一点。。一点就好

#include<bits/stdc++.h>
using namespace std;
const int N=60010;
inline int read()
{
    char ch=getchar(); int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
    return x*f;
}
struct edge{int y,next;}e[N];int len,first[N];
void ins(int x,int y){e[++len]=(edge){y,first[x]},first[x]=len;}
struct node{int son[2],s[2],d,f,p;}t[N<<1];
int tot,rt,a[N],dep[N<<1],al[N],ar[N],z[N];
void upd(int x)
{
    int lc=t[x].son[0],rc=t[x].son[1];
    t[x].s[0]=t[lc].s[0]^t[rc].s[0],t[x].s[1]=t[lc].s[1]^t[rc].s[1];
    if(dep[x])t[x].s[1]^=t[x].d;
    else t[x].s[0]^=t[x].d;
}
void rotate(int x,int &k)
{
    int y=t[x].f,z=t[y].f;
    if(y==k)k=x;
    else t[z].son[t[z].son[1]==y]=x;
    int w=(x==t[y].son[1]),g=t[x].son[!w];
    t[g].f=y,t[y].son[w]=g;
    t[y].f=x,t[x].son[!w]=y;
    t[x].f=z;
    upd(y);
}
void splay(int x,int &k)
{
    while(x!=k)
    {
        int y=t[x].f,z=t[y].f;
        if(y!=k)
        {
            if( (t[z].son[1]==y)==(t[y].son[1]==x) )rotate(y,k);
            else rotate(x,k);
        }
        rotate(x,k);
    }
    upd(x);
}
void in(int fa,int x)
{
    splay(fa,rt);
    int r=t[fa].son[1]; while(t[r].son[0])r=t[r].son[0];
    splay(r,t[fa].son[1]); t[r].son[0]=x,t[x].f=r;
    upd(r),upd(fa);
}
void dfs(int x,int fa)
{
    dep[x]=!dep[fa];
    if(fa)
    {
        t[al[x]].son[1]=ar[x],t[ar[x]].f=al[x];
        t[al[x]].d=a[x]; upd(al[x]);
        in(fa,x);
    }
    for(int k=first[x];k;k=e[k].next)dfs(e[k].y,x);
}
int main()
{
    int n=read(),l=read()+1,i,u,x,y;
    for(i=1;i<=n;i++)a[i]=read()%l,z[i]=al[i]=i,ar[i]=i+n;
    for(i=1;i<n;i++)x=read(),y=read(),ins(x,y);
    tot=n<<1,rt=1;
    t[1].son[1]=n+1,t[1].d=a[1],t[n+1].f=1; upd(1);
    dfs(1,0);
    int m=read(),nw=0,ans;
    while(m--)
    {
        u=read();
        if(u==1)
        {
            x=z[read()^nw];
            splay(al[x],rt),splay(ar[x],t[rt].son[1]);
            ans=t[ t[ar[x]].son[0] ].s[ !dep[x] ];
            if(!ans)printf("GTY\n");
            else printf("MeiZ\n"),nw++;
        }
        else if(u==2)
        {
            x=al[ z[read()^nw] ],y=read()^nw;
            splay(x,rt);
            t[x].s[ dep[x] ]^=t[x].d,t[x].d=y%l;
        }
        else
        {
            x=read()^nw,y=read()^nw,u=read()^nw;
            x=z[x],z[y]=y=++n, al[y]=++tot,ar[y]=++tot;
            dep[al[y]]=!dep[al[x]], t[al[y]].d=u%l;
            t[ar[y]].f=al[y],t[al[y]].f=al[x];
            upd(al[y]); in(al[x],al[y]);
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值