[博弈 && Splay维护DFS序]BZOJ3729 .Gty的游戏

可以看成巴什博弈和NIM的游戏

权值全部对L+1取模,然后只看子树中奇数层的亦或和是不是零就可以了。

因为强制在线,所以只能有Splay来维护DFS序

#include 
#include 
#include 
#include 

using namespace std;

const int N=500010;

map<int,int> M;
int G[N],w[N],dpt[N];
int n,m,lst,cnt,iL;
struct edge{
    int t,nx;
}E[N];
struct NODE{
    NODE *l,*r,*f;
    int val[2],w,dpt;
    NODE(){ val[0]=val[1]=w=dpt=0; l=r=f=0; }
}a[N],*L[N],*R[N];

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
    char c=nc(); x=0;
    for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void fix(int &x){
    if(!M.count(x)) M[x]=++cnt;
    x=M[x];
}

int cnt0;

inline void Insert(int x,int y){
    E[++cnt0].t=y; E[cnt0].nx=G[x]; G[x]=cnt0;
    E[++cnt0].t=x; E[cnt0].nx=G[y]; G[y]=cnt0;
}

int Q[N],t;

void dfs(int x,int f){
    Q[++t]=x; L[x]=a+t; dpt[x]=dpt[f]+1;
    for(int i=G[x];i;i=E[i].nx)
        if(E[i].t!=f) dfs(E[i].t,x);
    t++; R[x]=a+t;
}

inline void Up(NODE *x){
    if(!x) return ;
    x->val[0]=x->val[1]=0;
    x->val[(x->dpt)&1]=x->w;
    if(x->l)
        x->val[0]^=x->l->val[0],x->val[1]^=x->l->val[1];
    if(x->r)
        x->val[0]^=x->r->val[0],x->val[1]^=x->r->val[1];
}

inline void rotatel(NODE *x){
    NODE *y=x->f,*z=y->f;
    if(z) if(z->l==y) z->l=x; else z->r=x;
    x->f=z;
    if(y->l=x->r) y->l->f=y;
    x->r=y; y->f=x; 
    Up(y); Up(x);
}

inline void rotater(NODE *x){
    NODE *y=x->f,*z=y->f;
    if(z) if(z->l==y) z->l=x; else z->r=x;
    x->f=z;
    if(y->r=x->l) y->r->f=y;
    x->l=y; y->f=x; Up(y); Up(x);
}

inline void splay(NODE *x,NODE *t){
    while(x->f!=t){
        NODE *y=x->f,*z=y->f;
        if(x==y->l){
            if(z && z->l==y && z!=t) rotatel(y);
            rotatel(x);
        }
        else{
            if(z && z->r==y && z!=t) rotater(y);
            rotater(x);
        }
    }
}

inline int Query(int x){
    splay(L[x],0); 
    splay(R[x],L[x]);
    return R[x]->l?R[x]->l->val[(dpt[x]&1)^1]:0;
}

inline NODE *pre(NODE *x){
    if(x->l){
        x=x->l;
        while(x->r) x=x->r;
        return x;
    }
    while(x==x->f->l) x=x->f;
    return x->f;
}

void PUTS(NODE *x){
    if(x->l) PUTS(x->l);
    printf("%d ",x->w);
    if(x->r) PUTS(x->r);
}

int main(){
    rea(n); rea(iL); iL++; cnt=n;
    for(int i=1;i<=n;i++) 
        rea(w[i]),w[i]%=iL,M[i]=i;
    for(int i=1,x,y;i1,0);
    for(int i=2;i<=t;i++)
        a[i-1].r=a+i,a[i].f=a+i-1;
    for(int i=t;i;i--)
        a[i].w=w[Q[i]],a[i].dpt=dpt[Q[i]],Up(a+i);
    rea(m);
    while(m--){
        int opt,u,v,x;
        rea(opt);
        if(opt==1){
            rea(v); v^=lst; 
            fix(v); 
            puts(Query(v)?(lst++,"MeiZ"):"GTY"); 
        }
        else if(opt==2){
            rea(u); rea(x); u^=lst; x^=lst; 
            fix(u);
            splay(L[u],0); L[u]->w=x%iL; Up(L[u]);
        }
        else{
            rea(u); rea(v); rea(x); 
            u^=lst; v^=lst; x^=lst;
            fix(u); fix(v);
            dpt[v]=dpt[u]+1;
            t++; L[v]=a+t; 
            t++; R[v]=a+t;
            L[v]->dpt=dpt[v]; L[v]->w=x%iL;
            L[v]->r=R[v]; R[v]->f=L[v];
            NODE *cur=pre(R[u]);
            splay(cur,0); 
            splay(R[u],cur);
            R[u]->l=L[v]; L[v]->f=R[u]; Up(R[u]); Up(cur);
            splay(L[v],0);
        }
        //NODE *s;
        //for(int i=1;i<=t;i++) if(!a[i].f) s=a+i;
        //PUTS(s); putchar('\n');
    }
    return 0;
}

你可能感兴趣的:(平衡树,博弈论)