• [BZOJ3729]Gty的游戏


    [BZOJ3729]Gty的游戏

    试题描述

    某一天gty在与他的妹子玩游戏。
    妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问
    将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
    gty很快计算出了策略。
    但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
    gty不忍心打击妹子,所以他将这个问题交给了你。
    另外由于gty十分绅士,所以他将先手让给了妹子。

    输入

    第一行两个数字,n和L,n<=5*10^4,L<=10^9
    第二行n个数字,表示每个节点初始石子数。
    接下来n-1行,每行两个整数u和v,表示有一条从u到v的边。
    接下来一行一个数m,表示m组操作。
    接下来m行,每行第一个数字表示操作类型
    若为1,后跟一个数字v,表示询问在v的子树中做游戏先手是否必胜。
    若为2,后跟两个数字x,y表示将节点x的石子数修改为y。
    若为3,后跟三个数字u,v,x,表示为u节点添加一个儿子v,初始石子数为x。
    在任意时刻,节点数不超过5*10^4。

    输出

    对于每个询问,若先手必胜,输出"MeiZ",否则输出"GTY"。
    另,数据进行了强制在线处理,对于m组操作,除了类型名以外,都需要异或之前回答为"MeiZ"的个数。

    输入示例

    2 1000
    0 0
    1 2
    1
    1 1

    输出示例

    GTY

    数据规模及约定

    见“输入

    题解

    首先对于每个节点上石子的个数我们可以对 L + 1 取模,因为每次只能取不超过 L 个。考虑一场新的博弈:有一堆石子,大小为 x,每次可以取 1 ~ L 个石子,最终无法取石子的人输。那么显然当 x <= L 时,先手必胜;x = L + 1 时,先手必输;然后就可以推出 x % (L + 1) = 0 时先手必输,否则先手必赢(想一想,为什么)。

    然后发现如果假定当前子树根节点深度为 0,那么深度为偶数的节点上石子可以忽略,因为假设 A 先将偶数层上某节点的 t 个石子往上移动一层,那么 B 一定能再次将这 t 个石子再往上移动一层,直到最后到达根节点的那一步一定是 B 操作的。

    有了上面的结论,两个玩家的目的就是把奇数层的所有石子往上推 1 层即可,最后如果轮到玩家 A,但奇数层没有石子了,那么 A 输。

    这就转化成了经典的 Nim 问题:n 堆石子,每次可以取一堆中任意非零数量的石子,问谁能最后一步取完。(详见百度百科:戳这儿

    括号序列 + splay,维护奇数、偶数层的异或和,支持点插入、点修改操作。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    int read() {
        int x = 0, f = 1; char c = getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
        return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    #define maxnode 200010
    #define LL long long
    
    int m, head[maxn], next[maxm], to[maxm];
    void AddEdge(int a, int b) {
    	to[++m] = b; next[m] = head[a]; head[a] = m;
    	swap(a, b);
    	to[++m] = b; next[m] = head[a]; head[a] = m;
    	return ;
    }
    int clo, dl[maxn], dr[maxn], dep[maxn], inV[maxn], Dep[maxnode], Val[maxnode];
    void dfs(int u, int pa) {
    	dl[u] = ++clo; Dep[clo] = dep[u]; Val[clo] = inV[u];
    	for(int e = head[u]; e; e = next[e]) if(to[e] != pa) {
    		dep[to[e]] = dep[u] + 1;
    		dfs(to[e], u);
    	}
    	dr[u] = ++clo;
    	return ;
    }
    
    struct Node {
    	int v, siz, sum[2]; bool dep;
    	Node() {}
    	Node(int _, bool __): v(_), dep(__) {}
    } ns[maxnode];
    int fa[maxnode], ch[maxnode][2], L;
    void maintain(int o) {
    	ns[o].siz = 1; ns[o].sum[0] = ns[o].v * (ns[o].dep ^ 1); ns[o].sum[1] = ns[o].v * ns[o].dep;
    	for(int i = 0; i < 2; i++) if(ch[o][i]) {
    		ns[o].siz += ns[ch[o][i]].siz;
    		for(int j = 0; j < 2; j++) ns[o].sum[j] ^= ns[ch[o][i]].sum[j];
    	}
    	return ;
    }
    void build(int& o, int l, int r) {
    	if(l > r){ o = 0; return ; }
    	int mid = l + r >> 1; ns[o = mid] = Node(Val[mid], Dep[mid] & 1);
    	build(ch[o][0], l, mid - 1); build(ch[o][1], mid + 1, r);
    	if(ch[o][0]) fa[ch[o][0]] = o;
    	if(ch[o][1]) fa[ch[o][1]] = o;
    	return maintain(o);
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(z) ch[z][ch[z][1]==y] = u;
    	if(ch[y][1] == u) swap(l, r);
    	fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    	ch[y][l] = ch[u][r]; ch[u][r] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    void splay(int u) {
    	while(fa[u]) {
    		int y = fa[u], z = fa[y];
    		if(z) {
    			if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
    			else rotate(y);
    		}
    		rotate(u);
    	}
    	return ;
    }
    int splitl(int u) {
    	splay(u);
    	int tmp = ch[u][0];
    	fa[tmp] = ch[u][0] = 0;
    	return maintain(u), tmp;
    }
    int splitr(int u) {
    	splay(u);
    	int tmp = ch[u][1];
    	fa[tmp] = ch[u][1] = 0;
    	return maintain(u), tmp;
    }
    int merge(int a, int b) {
    	if(!a) return b;
    	if(!b) return a;
    	while(ch[a][1]) a = ch[a][1];
    	splay(a);
    	ch[a][1] = b; fa[b] = a;
    	return maintain(a), a;
    }
    void Split(int ql, int qr, int& lrt, int& mrt, int& rrt) {
    	lrt = splitl(ql); mrt = qr; rrt = splitr(mrt);
    //	printf("Split %d %d -> %d %d %d
    ", ql, qr, lrt, mrt, rrt);
    	return ;
    }
    void Merge(int a, int b, int c) {
    	a = merge(a, b); merge(a, c);
    	return ;
    }
    int query(int u) {
    	int lrt, mrt, rrt;
    	Split(dl[u], dr[u], lrt, mrt, rrt);
    	int ans = ns[mrt].sum[(Dep[dl[u]]&1)^1];
    //	printf("%d ", ans);
    	Merge(lrt, mrt, rrt);
    	return ans;
    }
    
    #define MOD 50007
    int hd[MOD], nxt[maxn], val[maxn], ToT;
    void insert(int v) {
    	int x = v % MOD;
    	val[++ToT] = v; nxt[ToT] = hd[x]; hd[x] = ToT;
    	return ;
    }
    int gid(int v) {
    	int x = v % MOD;
    	for(int e = hd[x]; e; e = nxt[e]) if(val[e] == v)
    		return e;
    	return 0;
    }
    
    int main() {
    	int n = read(); L = read() + 1;
    	for(int i = 1; i <= n; i++) inV[i] = read() % L, insert(i);
    	for(int i = 1; i < n; i++) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	dfs(1, 0);
    //	for(int i = 1; i <= n; i++) printf("%d: [%d, %d]
    ", i, dl[i], dr[i]);
    	int tmp = 0; build(tmp, 1, clo);
    	
    	int q = read(), lst = 0;
    	while(q--) {
    		int tp = read();
    		if(tp == 1) {
    			int u = gid(read() ^ lst);
    			if(query(u)) puts("MeiZ"), lst++;
    			else puts("GTY");
    		}
    		if(tp == 2) {
    			int u = dl[gid(read()^lst)];
    			splay(u);
    			ns[u].v = (read() ^ lst) % L;
    			maintain(u);
    		}
    		if(tp == 3) {
    			int u = gid(read() ^ lst), v = read() ^ lst, x = (read() ^ lst) % L;
    			insert(v); v = gid(v);
    			dl[v] = ++clo; dr[v] = ++clo;
    			Dep[dl[v]] = Dep[dl[u]] + 1;
    			Val[dl[v]] = x;
    			int lrt = dl[u], mrt = 0, rrt = splitr(lrt);
    			build(mrt, dl[v], dr[v]);
    			mrt = merge(lrt, mrt); merge(mrt, rrt);
    		}
    	}
    //	printf("%d %d
    ", clo, ToT);
    	
    	return 0;
    }
    
  • 相关阅读:
    oracle-高级查询
    java-集合框架
    java-String-StringBuffer
    ROS消息, 服务, 主题, 订阅 5
    ROS消息, 服务, 主题, 订阅 4
    ROS消息, 服务, 主题, 订阅 3
    ROS消息, 服务, 主题, 订阅 2
    ROS消息, 服务, 主题, 订阅 1
    可交互的Marker
    RVIZ建Maker
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6259547.html
Copyright © 2020-2023  润新知