[BZOJ 4202石子游戏] 博弈 + LCT

博弈博弈博弈 owo Problem 4202. -- 石子游戏

4202: 石子游戏

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 57  Solved: 20
[Submit][Status][Discuss]

Description

石子游戏是大家都很喜欢玩的一类游戏,这类游戏通常与石子的移动和取
舍有关,往往可以让人在游戏中获得不少的乐趣。
有一类树上石子游戏的规则是这样的:在一棵有根树上,每个节点都有着
一定数目的石子,两个玩家轮流进行游戏。每次,每个玩家可以把不超过 m 个
的石子移动到它的父亲上。显然,根节点没有父亲,故每个石子一旦移动到根
节点便无法再次移动。问题是以某个节点为根的子树进行这样的游戏,是否存
在先手必胜策略。
为了增加这个游戏的难度,我们对这个游戏进行一些小小的修改。现在,
我们的这棵树可能会长出新的节点。同时,每个节点上的石子数目可能会变化。
请问,以某个节点为根的子树进行这样的石子游戏,是否存在先手必胜策略。

Input

第一行包含两个数字 n 和 m,表示初始时有 n 个节点,
每次移动不能超过 m 个。
第二行 n 个正整数 a1,a2...an,表示初始时候的石子数量,其中 1 号节
点为根节点。
接下来 n   1 行,每行两个整数 u 和 v,表示有一条从 u 到 v 的边。
接下来一行一个数 t,表示操作的数目。
接下来 t 行,每行代表一个操作,每行的第一个数字代表操作类型,其中:
若为 1,后跟一个数字 v,表示询问在 v 的子树中做游戏先手是否必胜。
若为 2,后跟两个数字 x, y 表示将节点 x 的石子数修改为 y。
若为 3,后跟三个数字 u, v, x,表示为 u 节点添加一个儿子 v,初始石
子数为 x。

Output

对于每一个询问,若先手必胜输出“Yes”,否则输出“No”。 注,数据进行了强制在线处理,对于每一个操作,除类型名外,都需要异 或之前回答为“Yes“的数目。

Sample Input

2 1000 0 0 1 2 1 1 1

Sample Output

No HINT 对于100%的数据, n,t <= 50000。 同时,保证任何时刻树中节点数目和编号都不会超过 100000。 其余数据的范围皆在int范围内。

题解

对于跳到某一个根,我们可以想到阶梯博弈---->将所有奇数高度台阶的sg进行nim游戏,这个就是奇数高度的树上的sg值进行nim了.其阶梯博弈的意义就是如果先手移动偶数台阶的棋子,那么后手必定将移动过来的棋子再移一格使奇偶不变,最终局面不发生改变. 而对于每次不移动超过m,结论就是%(m+1) 那么这道题就是开两颗LCT,一棵树维护奇数深度的所有信息,一棵维护偶数深度的所有信息,每次修改链修改,每次查询子树查询,.

code

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define zig(x) zigzag(x,1)
#define zag(x) zigzag(x,2)
using namespace std;
const int maxn = 3e5+5;
int n,m;
int A[maxn];
struct LCT{
    int ls[maxn],rs[maxn],fa[maxn],val[maxn],laz[maxn],rev[maxn];
    void ptd(int x) {
        if(laz[x]) {
            val[ls[x]]^=laz[x];
            val[rs[x]]^=laz[x];
            laz[ls[x]]^=laz[x];
            laz[rs[x]]^=laz[x];
            laz[x] = 0;
        }
        if(rev[x]) {
            rev[x]^=1;
            rev[ls[x]]^=1; rev[rs[x]]^=1;
            swap(ls[x],rs[x]);
        }
    }
    void ptdall(int x) {
        if(!isroot(x)) ptdall(fa[x]);
        ptd(x);
    }
    bool isroot(int x) { return ls[fa[x]]!=x&&rs[fa[x]]!=x; }
    void zigzag(int x,int dft) {
        int y = fa[x] , z = fa[y];
        if(!isroot(y)) {
            if(ls[z]==y) ls[z] = x; else rs[z] = x;
        } 
        fa[x] = z; fa[y] = x;
        if(dft==1) {
            ls[y] = rs[x];
            fa[ls[y]] = y;
            rs[x] = y;
        } else {
            rs[y] = ls[x];
            fa[rs[y]] = y;
            ls[x] = y;
        }
    }
    void splay(int x) {
        int y , z;
        ptdall(x);
        while(!isroot(x)) {
            y = fa[x] ; z = fa[y];
            if(isroot(y)) {
                if(ls[y]==x) zig(x); else zag(x);
            } else{
                if(ls[z]==y) {
                    if(ls[y]==x) zig(y),zig(x);
                    else zag(x),zig(x);
                } else {
                    if(rs[y]==x) zag(y),zag(x);
                    else zig(x),zag(x);
                }
            }
        }
    }
    void acc(int x) {
        for(int y=0;x;y=x,x=fa[x]) {
            splay(x);
            rs[x] = y;
        }
    }
    void setroot(int x) {
        acc(x); splay(x); rev[x]^=1;
    }
    void link(int x,int ff) {
        setroot(x); fa[x] = ff;
    }
    void change(int x,int O) {
        setroot(1); acc(x);
        splay(x); laz[x]^=O; val[x]^=O;
        return;
    }
    int query(int x) {
        setroot(1); acc(x); splay(x);
        return val[x];
    }
}odd,eve;
int la[maxn],en[maxn],nt[maxn],owo,dep[maxn];
void adg(int x,int y) {
    en[++owo]=y; nt[owo]=la[x]; la[x]=owo;
}
void DFS(int x,int ba){
    dep[x] = dep[ba]+1;
    for(int it=la[x];it;it=nt[it]) {
        int y = en[it];
        if(y==ba) continue;
        DFS(y,x);
    }
    if(ba) odd.link(x,ba),eve.link(x,ba);
}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
    char t=GC;
    int x=0;
    while(!isdigit(t)) t=GC;
    while(isdigit(t)) x=x*10+t-48,t=GC;
    return x;
}
int main() {
    n=R(); m = R();
    int cnt = 0;
    for(int i=1;i<=n;i++) {
        A[i]=R(); A[i]%=(m+1);
    }
    for(int i=1;i<n;i++) {
        int x,y; x=R();y=R();
        adg(x,y); adg(y,x);
    }
    DFS(1,0);
    for(int i=1;i<=n;i++) {
        if(dep[i]&1) odd.change(i,A[i]);
        else eve.change(i,A[i]);
    }
    int t; t=R();
    int op,x,y,z;
    int WOC = 0;
    for(int i=1;i<=t;i++) {
        op=R();
        if(op==1) {
            x=R();x^=cnt;
            int oo = 0;
            if(dep[x]&1) oo = eve.query(x);
            else oo = odd.query(x);
    //      cerr<<(++WOC)<<endl;
            if(oo!=0) cnt++,puts("Yes");
            else puts("No");
        } else if(op==2) {
            x=R();y=R();
            x^=cnt; y^=cnt;
            y%=(m+1);
            if(dep[x]&1) odd.change(x,A[x]^y),A[x]=y;
            else eve.change(x,A[x]^y),A[x]=y;
        } else {
            x=R();y=R();z=R();
            x^=cnt; y^=cnt; z^=cnt; z%=(m+1);
            dep[y] = dep[x] + 1; A[y] = z;
            odd.link(x,y); eve.link(y,x);
            if(dep[y]&1) odd.change(y,z);
            else eve.change(y,z);
        }
    }
}
posted @ 2019-01-21 15:10  Newuser233  阅读(5)  评论(0编辑  收藏  举报