题面传送门

介于自己以前既没有写过 Staircase-Nim 的题解,也没写过时间轴分块的题解,所以现在就来写一篇吧(fog

首先考虑最极端的情况,如果图是一条链,并且链的一个端点是 \(1\),那么问题可以转化为序列上的问题,即可视作有一个 \(n\) 级的阶梯,第 \(i\) 级台阶上有 \(a_i\) 个石子,每次可以选择一堆并将其中 \(x(x\le L)\) 个石子向下移动一级,不能移动最底下一级的石子,不能操作者输。

这是一个经典的 staircase 博弈的模型,对于这样的模型我们有一个结论:我们并不用关心奇数级台阶上的石子的情况,只用把偶数级台阶上石子的 SG 值异或起来就是最终游戏的异或值。因为如果先手有必胜策略那么一旦后手将奇数级台阶上的石子移动到了偶数级台阶上,那么先手一定可以将移动的这部分石子再移动到奇数级台阶上,后手有必胜策略的情况也如此。对于此题而言,一堆 \(x\) 个石子的 SG 值显然是 \(x\bmod(L+1)\),因此整个游戏的异或值就是所有 \(i\bmod 2=0\) 的 \(a_i\bmod(L+1)\) 的异或和。这个结论放到树上也是成立的,因此对于一次询问 \(v\) 子树的答案而言,如果子树内所有深度与 \(v\) 的深度奇偶性相同的节点的 \(a_i\bmod(L+1)\) 的异或和为 \(0\) 答案就是 GTR,否则答案是 MeiZ

接下来考虑原问题怎么求解。如果允许离线那我们显然离线建出最终形态的树之后 DFS 序+BIT 即可解决。但是这题不可以离线还要支持插入新点操作,这就使问题变得略有点棘手。LCT 看似可做可我不会。因此考虑 P2137 Gty 的妹子树(怎么又是 Gty/jy)的套路,我们对时间轴分块,每 \(\sqrt{n}\) 次操作重新建树 DFS 一遍,对于已经在重构过的树中的部分的贡献,显然直接 DFS 序+BIT 或者分块即可求出,对于不在重构过的树中的点,我们就暴力开一个 vector,表示上一次重构到这次询问新加入了哪些点,然后每次遍历一遍 vector,在新加入一个点的时候记录一下这个点在重构好的树中哪个点的子树中即可判断该点是否在待查询的点的子树内。如果待查询的点不在重构的树中,那么显然其子树内的点肯定也不在重构好的树中,这样其子树内的点的个数肯定 \(\sqrt{n}\) 级别的。我们就暴力 DFS 找出其子树内的点计算贡献即可。

时间复杂度 \(n\sqrt{n}\)。

讲个笑话,BZOJ 上不重构,复杂度平方竟然过了(

const int MAXN=1e5;
const int BLK=225;
int n,L,a[MAXN+5];link_list<int,MAXN,MAXN*2> g;
int dep[MAXN+5],bgt[MAXN+5],edt[MAXN+5],tim=0,rid[MAXN+5],con[MAXN+5];
bool fin[MAXN+5];int fa[MAXN+5];
void dfs(int x,int f){
rid[bgt[x]=++tim]=x;fin[x]=1;con[x]=x;fa[x]=f;
for(int e=g.hd[x];e;e=g.nxt[e]){
int y=g.val[e];if(y==f) continue;
dep[y]=dep[x]+1;dfs(y,x);
} edt[x]=tim;
}
namespace divblk{
int blk_sz,blk_cnt,L[322],R[322],bel[MAXN+5];
int sum_blk[2][MAXN+5],sum_tot[2][322];
void init(){
blk_sz=316;blk_cnt=317;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,MAXN);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
}
void add(int x,int v,int id){
for(int i=x;i<=R[bel[x]];i++) sum_blk[id][i]^=v;
for(int i=bel[x];i<=blk_cnt;i++) sum_tot[id][i]^=v;
}
int query(int x,int id){
if(!x) return 0;
return sum_blk[id][x]^sum_tot[id][bel[x]-1];
}
void clear(){
memset(sum_blk,0,sizeof(sum_blk));
memset(sum_tot,0,sizeof(sum_tot));
}
void rebuild(int n){
clear();
for(int i=1;i<=n;i++){
sum_blk[dep[rid[i]]&1][i]=a[rid[i]];
sum_tot[dep[rid[i]]&1][bel[i]]^=a[rid[i]];
}
for(int _=0;_<2;_++) for(int i=1;i<=blk_cnt;i++){
for(int j=L[i]+1;j<=R[i];j++) sum_blk[_][j]^=sum_blk[_][j-1];
sum_tot[_][i]^=sum_tot[_][i-1];
}
}
}
vector<int> nw;
void rebuild(){
tim=0;memset(fa,0,sizeof(fa));dfs(1,0);
nw.clear();divblk::rebuild(tim);
}
bool in[MAXN+5];
void dfs_fnd(int x,int f){
in[x]=1;
for(int e=g.hd[x];e;e=g.nxt[e]){
int y=g.val[e];if(y==f) continue;
dfs_fnd(y,x);
}
}
void clr(int x,int f){
in[x]=0;
for(int e=g.hd[x];e;e=g.nxt[e]){
int y=g.val[e];if(y==f) continue;
clr(y,x);
}
}
bool vis[MAXN+5];
int main(){
scanf("%d%d",&n,&L);divblk::init();
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]%=(L+1);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),g.ins(u,v),g.ins(v,u);
rebuild();
int cnt=0,qu;scanf("%d",&qu);
for(int i=1;i<=qu;i++){
int opt;scanf("%d",&opt);
if(opt==1){
int x;scanf("%d",&x);x^=cnt;
if(fin[x]){
int res=divblk::query(edt[x],~dep[x]&1)^divblk::query(bgt[x]-1,~dep[x]&1);
for(int y:nw){
int z=con[y];
if(bgt[x]<=bgt[z]&&bgt[z]<=edt[x]&&((dep[y]^dep[x])&1)) res^=a[y];
} if(!res) puts("GTY");else puts("MeiZ"),cnt++;
} else {
int res=0;dfs_fnd(x,fa[x]);
for(int y:nw){
if(in[y]&&((dep[y]^dep[x])&1)) res^=a[y];
} if(!res) puts("GTY");else puts("MeiZ"),cnt++;
clr(x,fa[x]);
}
} else if(opt==2){
int x,y;scanf("%d%d",&x,&y);x^=cnt;y^=cnt;y%=(L+1);
if(fin[x]){
divblk::add(bgt[x],a[x],dep[x]&1);a[x]=y;
// printf("!!! %d %d %d\n",bgt[x],x,y);
divblk::add(bgt[x],a[x],dep[x]&1);
} else a[x]=y;
} else {
int u,v,y;scanf("%d%d%d",&u,&v,&y);
u^=cnt;v^=cnt;y^=cnt;y%=(L+1);a[v]=y;fa[v]=u;
assert(!vis[v]);
dep[v]=dep[u]+1;con[v]=con[u];nw.pb(v);
g.ins(u,v);g.ins(v,u);
} if(i%BLK==0) rebuild();
}
return 0;
}
/*
5 3
4 1 2 3 5
1 2
1 3
1 4
1 5
3
1 1
2 4 5
1 0
*/

BZOJ 3729 - Gty的游戏(Staircase 博弈+时间轴分块)的更多相关文章

  1. BZOJ 3729 GTY的游戏

    伪ETT? 貌似就是Splay维护dfn = = 我们首先观察这个博弈 这个博弈直接%(l+1)应该还是很显然的 因为先手怎么操作后手一定能保证操作总数取到(l+1) 于是就变成阶梯Nim了 因为对于 ...

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

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

  3. BZOJ 3729 Gty的游戏 ——Splay

    很久很久之前,看到Treap,好深啊 很久之前看到Splay,这数据结构太神了. 之后学习了LCT. 然后看到Top-Tree就更觉得神奇了. 知道我见到了这题, 万物基于Splay 显然需要维护子树 ...

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

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

  5. [BZOJ3729]Gty的游戏

    [BZOJ3729]Gty的游戏 试题描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动 ...

  6. bzoj 3991: [SDOI2015]寻宝游戏 虚树 set

    目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...

  7. bzoj 3232: 圈地游戏

    bzoj 3232: 圈地游戏 01分数规划,就是你要最大化\(\frac{\sum A}{\sum B}\),就二分这个值,\(\frac{\sum A}{\sum B} \geq mid\) \( ...

  8. [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)

    [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash) 题面 扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列.比如HTT表示第一次正面朝上, ...

  9. [BZOJ 3731] Gty的超级妹子树 (树分块)

    [BZOJ 3731] Gty的超级妹子树 (树分块) 题面 给出一棵树(或森林),每个点都有一个值.现在有四种操作 1.查询x子树里>y的值有多少个 2.把点x的值改成y 3.添加一个新节点, ...

随机推荐

  1. javascript-jquery对象的其他处理

    一.对元素进行遍历操作 如果要遍历一个jquery对象,对其中每个匹配元素进行相应处理,那么可以使用each()方法. $("div").each(function(index,e ...

  2. oo第三次博客-JML规格

    这三周的作业主要是围绕以JML来约束代码开发,以确保程序的正确性与鲁棒性. Part 1:三次作业的实现与bug 第一次作业没有任何算法和数据结构上的难度,对于Path和PathContainer的各 ...

  3. OO_JAVA_JML系列作业_单元总结

    OO_JAVA_JML系列作业_单元总结 (1)梳理JML语言的理论基础.应用工具链情况 简单梳理 以下三者是jml规格里的核心,对一个方法功能和属性的限制: requires子句:规定方法的前置条件 ...

  4. elasticsearch使用ik中文分词器

    elasticsearch使用ik中文分词器 一.背景 二.安装 ik 分词器 1.从 github 上找到和本次 es 版本匹配上的 分词器 2.使用 es 自带的插件管理 elasticsearc ...

  5. 如何清理history

    工作中,需要清理history 清理当前会话历史命令    history -c 清理当前用户所有历史命令     echo > .bash_history     #在用户主目录执行此操作

  6. JVM:垃圾收集器与对象的"存活"问题

    垃圾收集器垃圾收集(Garbage Collection,GC).当需要排查各种内存溢出.内存泄露问题时,当垃圾收集成为系统更高并发量的瓶颈时,我们需要去了解GC和内存分配. 检查对象的"存 ...

  7. linux 蓝牙开发调试(rtl8821cs模块)

    刚调完rtl8821cs的wifi功能,项目需要打通蓝牙配网功能. 调试过程中遇到各种问题中间几乎放弃,倒腾了几天最后还是打通了,顺便记录下过程. 通信接口:SDIO @WiFi.Uart @BT;工 ...

  8. reorder-list leetcode C++

    Given a singly linked list L: L 0→L 1→-→L n-1→L n, reorder it to: L 0→L n →L 1→L n-1→L 2→L n-2→- You ...

  9. hdu 1058 Humble Numbers(构造?枚举?)

    题意: 一个数的质因子如果只是2,3,5,7中的若干个.则这个数叫做humble number. 例如:1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 1 ...

  10. Jmeter 踩坑记录(七)

    1.master连不上Slave机 解决方法:telnet 192.168.xx.xx 1099  看IP 端口通不通,如果通 OK,不通,检查关闭防火墙或者开放端口 2.salve 连不上 mast ...