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;
}