ICPC2019 西安邀请赛 E.Tree

ICPC2019 西安邀请赛 E.Tree

题目链接

https://nanti.jisuanke.com/t/39272

题目大意

给你一个 $n$ 个点的树,每个点上有一堆共 $a_i$ 个石子。三种操作:

  1. 将从 $1$ 到 $x$ 路径上的每个点与 $t$ 取与
  2. 将从 $1$ 到 $x$ 路径上的每个点与 $t$ 取或
  3. 将从 $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;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据