ICPC2019 西安邀请赛 E.Tree
题目链接
https://nanti.jisuanke.com/t/39272
题目大意
给你一个 $n$ 个点的树,每个点上有一堆共 $a_i$ 个石子。三种操作:
- 将从 $1$ 到 $x$ 路径上的每个点与 $t$ 取与
- 将从 $1$ 到 $x$ 路径上的每个点与 $t$ 取或
- 将从 $1$ 到 $x$ 路径上的每个点再加上一堆 $t$ 大小的石子堆做 $Nim$ 游戏,问是否先手必胜。
题目分析
首先将题目中的 $Nim$ 游戏转换为 路径上的异或和,异或和为 $0$ 则先手必败。那么显然题目就变成了按位置 $1$ 或 $0$ ,之后求异或和。使用树链剖分维护一下即可。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> using namespace std; const int maxn = 1e5 + 5; int n, m, t; int a[maxn]; int w[maxn]; int dep[maxn]; int fa[maxn]; vector <int> e[maxn]; int fc = 0; int f[maxn]; int p[maxn]; int num[maxn]; struct node { int l, r; int lc, rc; int sum; int lazy; int flag; }; struct st { node tree[maxn * 4]; int tc; int root; int pushdown(int pos){ for(int i=0;i<31;i++){ if((tree[pos].flag >> i) & 1){ if((tree[pos].lazy >> i) & 1){ int s; tree[tree[pos].lc].flag |= (1 << i); tree[tree[pos].lc].lazy |= (1 << i); s = ((tree[tree[pos].lc].r - tree[tree[pos].lc].l + 1) & 1); tree[tree[pos].lc].sum ^= ((((tree[tree[pos].lc].sum >> i) & 1) ^ s) << i); tree[tree[pos].rc].flag |= (1 << i); tree[tree[pos].rc].lazy |= (1 << i); s = ((tree[tree[pos].rc].r - tree[tree[pos].rc].l + 1) & 1); tree[tree[pos].rc].sum ^= ((((tree[tree[pos].rc].sum >> i) & 1) ^ s) << i); }else{ tree[tree[pos].lc].flag |= (1 << i); tree[tree[pos].lc].lazy ^= (((tree[tree[pos].lc].lazy >> i) & 1) << i); tree[tree[pos].lc].sum ^= (((tree[tree[pos].lc].sum >> i) & 1) << i); tree[tree[pos].rc].flag |= (1 << i); tree[tree[pos].rc].lazy ^= (((tree[tree[pos].rc].lazy >> i) & 1) << i); tree[tree[pos].rc].sum ^= (((tree[tree[pos].rc].sum >> i) & 1) << i); } } } tree[pos].lazy = 0; tree[pos].flag = 0; return 0; } int query_tree(int pos, int l, int r){ int mid = (tree[pos].l + tree[pos].r) / 2; if(tree[pos].l == l and r == tree[pos].r){ return tree[pos].sum; }else{ if(tree[pos].flag){ pushdown(pos); } if(r <= mid){ return query_tree(tree[pos].lc, l, r); }else if(l <= mid){ return query_tree(tree[pos].lc, l, mid) ^ query_tree(tree[pos].rc, mid + 1, r); }else{ return query_tree(tree[pos].rc, l, r); } } } int update_tree(int pos, int l, int r, int opt, int x){ int mid = (tree[pos].l + tree[pos].r) / 2; if(tree[pos].l == l and r == tree[pos].r){ if(opt == 1){ for(int i=0;i<31;i++){ if((x >> i) & 1){ tree[pos].flag |= (1 << i); tree[pos].lazy |= (1 << i); int s = ((tree[pos].r - tree[pos].l + 1) & 1); tree[pos].sum ^= ((((tree[pos].sum >> i) & 1) ^ s) << i); } } }else{ for(int i=0;i<31;i++){ if(((x >> i) & 1) == 0){ tree[pos].flag |= (1 << i); tree[pos].lazy ^= (((tree[pos].lazy >> i) & 1) << i); tree[pos].sum ^= (((tree[pos].sum >> i) & 1) << i); } } } }else{ if(tree[pos].flag){ pushdown(pos); } if(r <= mid){ update_tree(tree[pos].lc, l, r, opt, x); }else if(l <= mid){ update_tree(tree[pos].lc, l, mid, opt, x); update_tree(tree[pos].rc, mid + 1, r, opt, x); }else{ update_tree(tree[pos].rc, l, r, opt, x); } tree[pos].sum = tree[tree[pos].lc].sum ^ tree[tree[pos].rc].sum; } return 0; } int init_tree(int l, int r){ int mid = (l + r) / 2; int pos = ++tc; tree[pos].l = l; tree[pos].r = r; tree[pos].lazy = 0; tree[pos].flag = 0; if(l == r){ tree[pos].sum = a[num[l]]; }else{ tree[pos].lc = init_tree(l, mid); tree[pos].rc = init_tree(mid + 1, r); tree[pos].sum = tree[tree[pos].lc].sum ^ tree[tree[pos].rc].sum; } return pos; } int update(int l, int r, int opt, int x){ update_tree(root, l, r, opt, x); } int query(int l, int r){ return query_tree(root, l, r); } int init(){ tc = 0; root = init_tree(1, n); return 0; } } tree; bool cmp(int x, int y){ return w[x] > w[y]; } int read(){ int x; scanf("%d", &x); return x; } int dfsa(int x){ w[x] = 1; for(int y : e[x]){ if(y == fa[x])continue; fa[y] = x; dep[y] = dep[x] + 1; dfsa(y); w[x] += w[y]; } return 0; } int dfsb(int x, int fr){ int i; int y; p[x] = ++fc; num[fc] = x; f[x] = fr; if(e[x].size() == 1){ return 0; } i = 0; if(e[x][i] == fa[x]){ i++; } y = e[x][i]; dfsb(y, fr); for(++i;i<e[x].size();i++){ y = e[x][i]; dfsb(y, y); } return 0; } int query(int pos, int x){ while(pos){ x ^= tree.query(p[f[pos]], p[pos]); pos = f[pos]; pos = fa[pos]; } return x; } int update(int pos, int opt, int x){ while(pos){ tree.update(p[f[pos]], p[pos], opt, x); pos = f[pos]; pos = fa[pos]; } return x; } int main(){ int i, j; int x, y; int opt; n = read(); m = read(); for(i=1;i<=n;i++){ a[i] = read(); } for(i=1;i<n;i++){ x = read(); y = read(); e[x].push_back(y); e[y].push_back(x); } dep[x] = 1; dfsa(1); for(i=1;i<=n;i++){ sort(e[i].begin(), e[i].end(), cmp); } dfsb(1, 1); tree.init(); for(i=1;i<=m;i++){ opt = read(); x = read(); y = read(); if(opt == 1){ update(x, 1, y); }else if(opt == 2){ update(x, 2, y); }else{ printf(query(x, y) ? "YES\n" : "NO\n"); } } return 0; }