[JZOJ4759] 【雅礼联考GDOI2017模拟9.4】石子游戏
题目
描述
题目大意
在一棵树上,每个节点都有些石子。
每次将mmm颗石子往上移,移到根节点就不能移了。
双方轮流操作,问先手声还是后手胜。
有三种操作:
1、 询问以某个节点为根的答案。
2、 改变某个点的石子数。
3、 在树中加入一个点。
思考历程
这是一道博弈题。
意味着我连暴力都不会打。
所以放弃治疗。
正解
首先,偶数层的石子是没有意义的。
如果移动了偶数层的石子,另一方就可以模仿你的操作,继续移动这颗石子。
所以我们只需要考虑奇数层的石子,每次移动111到mmm颗石子,移动到上一层之后消失。
这就转化成了一个Nimk问题。
按照套路,将每个石子数模m+1m+1m+1(个人感性理解:当你移动111到mmm颗石子的时候,别人可以移动石子使得你们移的总数为m+1m+1m+1)
然后异或起来,如果为000就必败,反之必胜。
然后这题就差不多做完了。
我们只需要维护子树中偶数层的异或和就可以了。
LCT?ETT?
都行。
在维护的时候可以分别建立两棵树,以111号点为准,偶数层和奇数层分别建一棵树。
对于某个节点,如果它在奇数层,那么奇数层的树中它有值,偶数层的树中值为000。
反之亦然。
这样处理起来就比较方便了。
话说这题真的有毒,说好保证编号不超过500005000050000,结果真香了。
害得我调试了至少一天半……
开到600006000060000就能过了。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <cassert>
#include <algorithm>
#define N 60010
struct Node *null;
struct Node{
Node *fa,*c[2];
bool is_root,rev;
int sum,su;
inline bool getson(){return fa->c[0]!=this;}
inline void update(){
sum=c[0]->sum^c[1]->sum^su;
}
inline void reserve(){
swap(c[0],c[1]);
rev^=1;
}
inline void pushdown(){
if (rev){
c[0]->reserve();
c[1]->reserve();
rev=0;
}
}
inline void push(){
if (!is_root)
fa->push();
pushdown();
}
inline void rotate(){
Node *y=fa,*z=y->fa;
if (y->is_root){
y->is_root=0;
is_root=1;
}
else
z->c[y->getson()]=this;
bool k=getson();
fa=z;
y->c[k]=c[k^1];
c[k^1]->fa=y;
c[k^1]=y;
y->fa=this;
sum=y->sum;
y->update();
}
inline void splay(){
push();
while (!is_root){
if (!fa->is_root){
if (getson()!=fa->getson())
rotate();
else
fa->rotate();
}
rotate();
}
}
inline Node *access(){
Node *x=this,*y=null;
for (;x!=null;y=x,x=x->fa){
x->splay();
x->su^=y->sum^x->c[1]->sum;
x->c[1]->is_root=1;
x->c[1]=y;
y->is_root=0;
x->update();
}
return y;
}
inline void mroot(){
access()->reserve();
}
inline void link(Node *y){
access();
splay();
y->mroot();
y->splay();
y->fa=this;
su^=y->sum;
update();
}
} d[2][N];
int n,m;
int a[N];
struct EDGE{
int to;
EDGE *las;
} e[N*2];
int ne;
EDGE *last[N];
bool col[N];
void build(int x,int fa){
d[col[x]][x]={null,null,null,1,0,0,a[x]};
d[col[x]^1][x]={null,null,null,1,0,0,0};
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa){
col[ei->to]=col[x]^1;
build(ei->to,x);
d[0][x].link(&d[0][ei->to]);
d[1][x].link(&d[1][ei->to]);
}
}
int main(){
null=new Node;
*null={null,null,null,0,0,0,0};
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]),a[i]%=m+1;
for (int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
last[u]=&(e[++ne]={v,last[u]});
last[v]=&(e[++ne]={u,last[v]});
}
build(1,0);
d[0][1].mroot(),d[1][1].mroot();
int T,lastans=0;
scanf("%d",&T);
while (T--){
int op;
scanf("%d",&op);
if (op==1){
int x;
scanf("%d",&x),x^=lastans;
Node *p=&d[col[x]^1][x];
p->access();
p->splay();
if (p->sum^p->c[0]->sum)
printf("Yes\n"),lastans++;
else
printf("No\n");
}
else if (op==2){
int x,y;
scanf("%d%d",&x,&y),x^=lastans,y^=lastans;
y%=m+1;
Node *p=&d[col[x]][x];
p->access();
p->splay();
p->su^=a[x]^y;
a[x]=y;
p->update();
}
else{
int u,v,x;
scanf("%d%d%d",&u,&v,&x),u^=lastans,v^=lastans,x^=lastans;
x%=m+1;
a[v]=x;
col[v]=col[u]^1;
d[col[v]][v]={null,null,null,1,0,0,x};
d[col[v]^1][v]={null,null,null,1,0,0,0};
d[0][u].link(&d[0][v]);
d[1][u].link(&d[1][v]);
}
}
return 0;
}
整篇似乎也没什么需要注释的……
总结
像这样的博弈类问题普遍有一个套路。
分为奇数层和偶数层,就可以不管偶数层。
然后直接处理奇数层即可。
[JZOJ4759] 【雅礼联考GDOI2017模拟9.4】石子游戏的更多相关文章
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)总结
考的还ok,暴力分很多,但有点意外的错误. 第一题找规律的题目,推了好久.100分 第二题dp,没想到. 第三题树状数组.比赛上打了个分段,准备拿60分,因为时间不够,没有对拍,其中有分段的20分莫名 ...
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)总结
第一题又有gcd,又有xor,本来想直接弃疗,不过后来想到了个水法: 当两个相邻的数满足条件时,那么他们的倍数也可能满足条件.然后没打,只打了个暴力. 正解就是各种结论,各种定理搞搞. 第二题,想都不 ...
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)公约数
题目 给定一个正整数,在[1,n]的范围内,求出有多少个无序数对(a,b)满足gcd(a,b)=a xor b. 分析 显然a=b是一定不满足, 我们设\(a>b\), 易得gcd(a,b)&l ...
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径
题目 给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E.(k为路径p上的边的权值和). 分析 点分治,设当前为x的,求在以x为根的子树中,经过x的路径(包括起点或 ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Binary
题目 分析 首先每个数对\(2^i\)取模.也就是把每个数的第i位以后删去. 把它们放进树状数组里面. 那么当查询操作, 答案就位于区间\([2^i-x,2^{i-1}-1-x]\)中,直接查询就可以 ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Value
题目 分析 易证,最优的答案一定是按\(w_i\)从小到大放. 我们考虑dp, 先将w从小到大排个序,再设\(f_{i,j}\)表示当前做到第i个物品,已选择了j个物品的最大值.转移就是\[f_{i, ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Matrix
题目 分析 假设,我们从\(F_{i,2}\)出发,那么对\(F_{n,n}\)的贡献就是\(某个系数乘以a^{n-i}b^{n-1}r_i\): 同理,如果从\(F_{2,i}\)出发,那么对\(F ...
- P7514-[省选联考2021A/B卷]卡牌游戏【贪心】
正题 题目链接:https://www.luogu.com.cn/problem/P7514 题目大意 给出\(n\)个卡牌有\(a_i/b_i\),开始都是\(a_i\)朝上,将不超过\(m\)张卡 ...
- 【GDOI2017 day1】取石子游戏 线段树+区间合并
题面 如果给你一棵有根树,树根为 1,并且树的每个结点上有一个权值,现在我想知道每个点,除它所在子树以外的结点权值集合的 mex,怎么做呢? 在这里,mex 是定义在集合上的函数,mex(S) 表示 ...
随机推荐
- tomcat部署项目报错NoSuchMethodException#addServlet,addFilter
java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet java.lang.NoSuchMethod ...
- 20140502 static_cast和dynamic_cast的类型检查 双链表建立,删除,打印
1.static_cast和dynamic_cast的类型检查 static_cast的类型检查:只检查无关类之间的转换 CBaseY* pY1 = static_cast<CBaseY*> ...
- 20140320 roc曲线 sizeof
1.roc曲线 http://www.zhizhihu.com/html/y2012/4076.html 2.using namespace std的缺点:程序中定义一个变量cout会被误认为是std ...
- Xcode常见路径
模拟器安装的位置: /Library/Developer/CoreSimulator/Profiles/Runtimes 可以通过Xcode安装 模拟器程序的沙盒 Xcode编译生成的Product ...
- ElasticSearch 增删改查
HTTP 协议本身语义:GET 获取资源.POST 新建资源(也可以用于更新资源).PUT 更新资源.DELETE 删除资源. ES通过HTTP Restful方式管理数据:1.格式:#操作 /ind ...
- 用shell脚本执行php删除缓存文件
<?php #定义删除路径//服务器缓存目录的路径 $path = '/www/wwwroot/****/data/runtime'; #调用删除方法 deleteDir($path); fun ...
- thinkphp 比较标签
比较标签用于简单的变量比较,复杂的判断条件可以用if标签替换,比较标签是一组标签的集合,基本上用法都一致,如下: <比较标签 name="变量" value="值& ...
- 解决Delphi 2010启动时卡死并报displayNotification堆栈溢出错误
1. 清理IE的历史记录,删除浏览器缓存(不需要清cookie) 2. 禁用startpage 2.1 从 Delphi 2010 启动菜单上点右键 -> 查看属性->快捷方式->目 ...
- 驱动层hook系统函数的时,如何屏蔽掉只读属性?
对于Intel 80486或以上的CPU,CR0的位16是写保护(Write Proctect)标志.当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向只读页面执行写操作:当该位复位时则 ...
- 1 A+B问题
原题网址: http://www.lintcode.com/zh-cn/problem/a-b-problem/# 给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符. 注意事项 你不需 ...
