[bzoj3729]Gty的游戏

来源:互联网 发布:java jsonarray清空 编辑:程序博客网 时间:2024/05/17 23:16

Description

给定一棵n个节点的数,第i个节点上有ai个石子。
有两个人在van游戏,每次操作者可以从x的子树中的任意一个点选择不超过m个石子移动到它的父亲。
给定t次操作,每次操作询问为x的子树中做游戏先手是否必胜,或者修改一个点的石子数量,又或者是给x新增一个儿子y,石子个数为z。
n,t<=50000,保证任何时刻树中结点个数和编号不超过50000

Solution

如果你看到了这里,先别急着往下看。
因为出题人有毒!!!
说好的结点个数不超过50000呢?

好了,现在我们来讲讲正解。
首先你得会经典NIM游戏。
我们先来分析一下sg函数值。
sg[x]=mexmin(x,m)i=1(sg[xi])sg[0]=0
归纳可得sg[x]=xmod(m+1)
然后,我们可以发现这是个阶梯NIM游戏。
简单点讲,我们只需要关注奇数层的异或和。(根节点的深度为0)
为什么呢?因为你移动偶数层,别人就可以立马把它移到奇数层。
所以移动偶数层等于没动。

然后就是要处理子树问题了。
动态加点可以用LCT,但子树处理似乎要用Euler Tour Tree…..
本蒟蒻不会写。。。
那么我们发现每次加入的点都是新的(似乎直接插入一棵子树也不是问题)
那么我们可以用splay来维护dfs序。
由于序列是动态的,所以我们需要动态维护每个点的size。
不过简单点想,一个节点所掌管的区间就是这个节点为左端点,节点右边第一个深度小于等于它自己的那个点为右端点。
于是我们可以维护区间min_dep值。
然后维护深度为奇数和偶数的层数的异或和。(奇数和总和我不拦着你)
注意这道题要在右边插入一个虚拟节点,但不用在左边插。
还有,插入没必要搞得那么麻烦,只插入一个点的话,直接插就好啦。

从a_crazy_czy那里学来的姿势,这道题可以用定期重构来做。
似乎还可以用树分块(Gty系列)。

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define rep(i,a) for(int i=last[a];i;i=next[i])#define N 100005#define Null N-1using namespace std;const int inf=0x7fffffff;int t[N][2],f[N],size[N],sg[N],sg_0[N],sg_1[N],dep[N];int d[N],n,m,q,x,y,z,l,tot,cnt,ans,bz,root;int last[N],to[N*2],next[N*2];void add(int x,int y) {    to[++l]=y;next[l]=last[x];last[x]=l;}void updata(int x) {    int l=t[x][0],r=t[x][1];    dep[x]=min(d[x],min(dep[l],dep[r]));    size[x]=size[l]+size[r]+1;    sg_0[x]=sg_0[l]^sg_0[r];    sg_1[x]=sg_1[l]^sg_1[r];    if (d[x]&1) sg_1[x]^=sg[x];    else sg_0[x]^=sg[x];}int son(int x) {return t[f[x]][1]==x;}void rotate(int x) {    int y=f[x],z=son(x);f[x]=f[y];    if (f[x]) t[f[x]][son(y)]=x;    if (t[x][1-z]) f[t[x][1-z]]=y;    f[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y;    updata(y);updata(x);}void splay(int x,int y) {    while (f[x]!=y) {        if (f[f[x]]!=y)             if (son(x)==son(f[x])) rotate(f[x]);            else rotate(x);        rotate(x);    }    if (!y) root=x;}void dfs(int x,int y) {    if (y) d[x]=d[y]+1;    if (root) f[x]=root,t[root][1]=x;    splay(x,0);    rep(i,x) if (to[i]!=y) dfs(to[i],x);}int get(int x,int y) {    if (dep[t[x][0]]<=y) return get(t[x][0],y);    else if (d[x]<=y) return x;    else return get(t[x][1],y);}int main() {    scanf("%d%d",&n,&m);d[0]=dep[0]=inf;    fo(i,1,n) scanf("%d",&sg[i]),sg[i]%=(m+1);    fo(i,1,n-1) scanf("%d%d",&x,&y),add(x,y),add(y,x);    d[1]=1;dfs(1,0);f[Null]=root;t[root][1]=Null;splay(Null,0);    for(scanf("%d",&q);q;q--) {        scanf("%d",&bz);        if (bz==1) {            scanf("%d",&x);x^=cnt;            splay(x,0);int y=get(t[x][1],d[x]);            splay(y,x);            if (d[x]&1) ans=sg_0[t[y][0]];            else ans=sg_1[t[y][0]];            if (ans) printf("MeiZ\n"),cnt++;            else printf("GTY\n");        } else if (bz==2) {            scanf("%d%d",&x,&y);x^=cnt;y^=cnt;            splay(x,0);sg[x]=y%(m+1);updata(x);        } else {            scanf("%d%d%d",&x,&y,&z);x^=cnt;y^=cnt;z^=cnt;            d[y]=d[x]+1;sg[y]=z%(m+1);            splay(x,0);f[t[x][1]]=y;f[y]=x;            t[y][1]=t[x][1];t[x][1]=y;            updata(t[y][1]);updata(y);updata(x);        }    }}
1 0
原创粉丝点击