题面

传送门

前置芝士

巴什博奕

\(Nim\)游戏的改版,我们现在每次最多只能取走\(k\)个石子,那么\(SG\)函数很容易写出来

\[SG(x)=mex_{i=1}^{\min(x,k)}SG(x-i)\]

有\(SG(0)=0\),用归纳法易知\(SG(x)=x\bmod (k+1)\)

阶梯博弈

有\(n\)级台阶,从\(0\)级开始数到\(n\)级。每级上都有一定的石子。每次可以把一个阶梯的石子往下移,\(0\)级阶梯的不能移,不能操作者输。

这里有一个结论,我们只需要考虑所有奇数层,该游戏就等价于\(Nim\)游戏

为啥嘞?

首先偶数层是不会有任何影响的,因为如果你移动偶数层若干个石子到奇数层,那么对手一定可以通过移动把你移的石子移到下一个偶数层,相当于这些石子仍然在偶数层。如果移动奇数层的石子,我们就默认它消失了

题解

那么这题就比较明显了,首先很容易算出每个节点的\(SG\)值,那么对于一个节点\(u\),如果它的深度是奇数,那么答案就是它子树里所有深度为偶数的节点的\(SG\)值的异或和之和,如果不为\(0\)说明妹子赢,否则\(gty\)赢

于是我们需要在线维护子树深度为奇数的节点的异或和以及深度为偶数的节点的异或和(代码里是维护子树总的异或和和深度为奇数的节点的异或和),并且还要资瓷插入节点

那么用\(ETT\)就好了(也就是\(Splay\)维护\(dfs\)序),而且这里只需要单括号欧拉序就可以了

不过这里有个问题是单括号欧拉序我该怎么找子树代表的区间呢?

如果直接维护\(size\)应该可以做,但是\(size\)还需要链修改非常麻烦。我们可以在\(Splay\)上二分,对于节点\(u\),找到\(dfs\)序比它大的节点中最小的满足\(dep[v]\leq dep[u]\)的节点\(v\),那么\([u,v)\)这个范围就是子树的范围了。同时为了避免\(1\)找不到对应的\(v\),要插入一个虚拟节点,深度设为\(0\),且\(dfs\)序最大

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=E[i].v;i;i=E[i].nx,v=E[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){R int res,f=1;R char ch;while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');return res*f;
}
inline int getop(){R char ch;while((ch=getc())>'9'||ch<'0');return ch-'0';}
const int N=1e5+5;
inline int min(R int x,R int y){return x<y?x:y;}
struct eg{int v,nx;}E[N<<1];int head[N],tot;
inline void add(R int u,R int v){E[++tot]={v,head[u]},head[u]=tot;}
struct node;typedef node* ptr;
struct node{ptr lc,rc,fa;int sum,s,d,v,mn;inline node();inline void init(R int ss,R int dd){mn=d=dd,sum=v=ss,s=ss*(d&1);}inline ptr upd(){mn=min(d,min(lc->mn,rc->mn)),sum=lc->sum^rc->sum^v,s=lc->s^rc->s^(v*(d&1));return this;}
}e[N],*rt;
inline node::node(){lc=rc=fa=e;}
void rotate(ptr &rt,ptr p){ptr s=p->fa,t=s->fa;if(s!=rt)(t->lc==s?t->lc:t->rc)=p;else rt=p;s->fa=p,p->fa=t;if(s->lc==p)s->lc=p->rc,p->rc->fa=s,p->rc=s->upd();else s->rc=p->lc,p->lc->fa=s,p->lc=s->upd();
}
void splay(ptr &rt,ptr p){while(p!=rt){if(p->fa!=rt)rotate(rt,p->fa->lc==p^p->fa->fa->lc==p->fa?p:p->fa);rotate(rt,p);}p->upd();
}
ptr get(ptr p,int d){while(true){if(p->lc->mn<=d)p=p->lc;else if(p->d<=d)return p;else p=p->rc;}
}
int n,m,q,tim,cnt,res,dep[N],dfn[N],rk[N],a[N];
void dfs(int u,int fa){dfn[u]=++tim,dep[u]=dep[fa]+1,rk[tim]=u;go(u)if(v!=fa)dfs(v,u);
}
void build(ptr &p,int l,int r,ptr fa){int mid=(l+r)>>1;p=e+rk[mid],p->fa=fa,p->init(a[rk[mid]],dep[rk[mid]]);if(l<mid)build(p->lc,l,mid-1,p);if(mid<r)build(p->rc,mid+1,r,p);p->upd();
}
int main(){
//  freopen("testdata.in","r",stdin);
//  freopen("testdata.out","w",stdout);n=read(),m=read(),e->d=e->mn=inf;fp(i,1,n)a[i]=read()%(m+1);for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);dfs(1,0),build(rt,1,tim,e);splay(rt,e+rk[tim]),rt->rc=(e+N-1),(e+N-1)->init(0,0),(e+N-1)->fa=rt,rt->upd();char op;int u,v,x;q=read();ptr s,t;while(q--){op=read();switch(op){case 1:{u=read()^cnt,s=e+u,splay(rt,s),t=get(s->rc,dep[u]);splay(s->rc,t);res=dep[u]&1?t->lc->s^t->lc->sum:t->lc->s;puts(res?(++cnt,"MeiZ"):"GTY");break;}case 2:{u=read()^cnt,v=read()^cnt,s=e+u,splay(rt,s);s->v=v%(m+1),s->upd();break;}case 3:{u=read()^cnt,v=read()^cnt,x=read()^cnt,s=e+u,t=e+v;dep[v]=dep[u]+1,a[v]=x%(m+1),t->init(a[v],dep[v]);splay(rt,s),s->rc->fa=t,t->rc=s->rc,t->fa=s,s->rc=t;t->upd(),s->upd();break;}}}return 0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10716560.html

BZOJ3729: Gty的游戏(伪ETT)相关推荐

  1. BZOJ 3729: Gty的游戏 [伪ETT 博弈论]【学习笔记】

    题意: 给定一棵有根树,每个节点有一些石子,每次可以将不多于k的石子移动到父节点 修改一个点的石子数,插入一个点,询问某棵子树是否先手必胜 显然是一个阶梯Nim 每次最多取k个,找规律或者观察式子易发 ...

  2. [bzoj3729]Gty的游戏

    Description 给定一棵n个节点的数,第i个节点上有ai个石子. 有两个人在van游戏,每次操作者可以从x的子树中的任意一个点选择不超过m个石子移动到它的父亲. 给定t次操作,每次操作询问为x ...

  3. 【BZOJ 3729】3729: Gty的游戏 (Splay维护dfs序+博弈)

    未经博主同意不得转载 3729: Gty的游戏 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 448  Solved: 150 Descriptio ...

  4. 【BZOJ3729】Gty的游戏,博弈+splay

    传送门 挺蛋疼的一道题 连想带做搞了一晚上晚自习+下午两节课 博弈方面还是很好弄的,就是"阶梯问题"+"Nim取模游戏" 分别维护深度为奇数和偶数的节点的sg函 ...

  5. BZOJ 3729: Gty的游戏

    这两三天貌似没怎么写blog 来补点 劲啊 这道题 我的数据结构真心菜.. 首先对于子树来搞 显然就是用dfs序 由于动态加点 我们用splay 考虑博弈 距离这层为偶数层的可以不管 奇数层的就像简单 ...

  6. 博弈论题表(好少~~~)

    bzoj2017:[Usaco2009 Nov]硬币游戏 *用了一小点思想的傻逼dp(记忆化搜索) bzoj1188:[HNOI2007]分裂游戏 **很神奇的把游戏拆分为子游戏的方法 bzoj102 ...

  7. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

  8. bzoj3786: 星系探索

    学到了新姿势,splay维护括号序列(听说是伪ETT(euler-tour-tree 欧拉搜索树)?) 大型工业题 注意点:1:结构改变了以后编号变成不连续的了,要找前驱和后继 2:就算lazy也需要 ...

  9. 众妙之门玄之又玄,游戏系统中的伪随机(Pseudo-Randomization)和真随机(True-Randomization)算法实现Python3

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_212 有人说,如果一个人相信运气,那么他一定参透了人生.想象一下,如果你在某款moba游戏中,在装备平平,队友天坑的情况下,却刀刀 ...

最新文章

  1. centos6.5命令安装redis并设置redis自启动,可远程连接
  2. @InsertProvider 实现批量插入数据
  3. 前后端完全分离出现跨域、无法访问后台解决方案
  4. php调用airtestide,raw device
  5. URI Is Not Registered
  6. ios 配置java环境变量_Ios 入门 ----基本的控件
  7. groovy定义变量获取当前时间_Groovy 变量 (Groovy 教程) – Groovy教程 中文开发手册 - Break易站...
  8. java微信模板消息开发,微信公众号模板消息开发小结
  9. 腾讯云如何申请免费服务器试用
  10. 苹果电脑教程之退出ID账号
  11. android ios mp4格式转换,ios格式转换器|iphone视频格式转换器免费版 7.1 - 系统天堂...
  12. 叉车AGV车载系统模块详解
  13. WGestures全局鼠标手势设置指南
  14. 派森小镇(二)神奇能量药丸
  15. 统计推断(二) Estimation Problem
  16. NOJ——1665夜神的思考(YY+组合问题+分类讨论)
  17. sorted()排序详解
  18. 【Hackathon】基于RKNPU2给FastDeploy仓库贡献代码
  19. 求出 2 到 n 之间 (含 n)的所有素数。
  20. 想转行网络安全行业,究竟是参加培训班还是靠自学?

热门文章

  1. MyCat的安装及基本使用(MySQL分库分表)
  2. Router_Cloud
  3. 【体系结构】Oracle体系结构的独特理解
  4. 在线最大公因数计算器
  5. 微积分28-复合函数与隐函数的微分法
  6. Python程序-打印单词的菱形字符图案
  7. 自学篇之----html的所有input标签 以及post和get提交之间的区别
  8. ubuntu 14.04 下 安装samba 及SSH 服务端的方法
  9. 数据结构练手02 双向链表实现
  10. 10g手动创建数据库