求树上简单路径的异或和【树链剖分】+【线段树】
支持,修改链上的值为
a
i
∣
t
a_i|t
ai∣t 以及
a
i
&
t
a_i\&t
ai&t
分析
对位考虑,每一位建立一颗线段树,维护链上值的位情况
-
假如是操作 1 1 1, a i ∣ t a_i|t ai∣t
只有当 t t t的某一位为 1 1 1的时才会对线段树进行更新,而且是区间 s e t set set为 1 1 1 -
假如是操作 2 2 2, a i & t a_i\&t ai&t
只有当 t t t的某一位为 0 0 0的时才会对线段树进行更新,而且是区间 s e t set set为 0 0 0
细节:
由于异或性质,长度为偶数的区间
s
e
t
set
set 1还是0,奇数才会有影响
这里要求的是是否能赢,而且是经典的
n
i
m
nim
nim博弈(不会的可以搜一下),只需要求链上的异或和与
t
t
t异或后是否为零即可
简单说一下,
n
i
m
nim
nim博弈任取石子的情况就是,所有堆二进制下的异或值是否为
0
0
0
为
0
0
0代表,只要先手执行一种操作,后手一定能够模仿这种操作,取这么多的石子,因为假如前者取的是
x
x
x个,二进制拆分为
010110
010110
010110,由于全部值异或为
0
0
0(全部二进制位都出现了偶数次),必然会有一种取法能够满足二进制拆分也是这样
010110
010110
010110
代码
//jsk39272-solve
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 5e5+5;
const ll MOD = 1e9+7;
int N, M, K;
int arr[MAX_N];
int head[MAX_N];
int tot = 0;
struct Edge{
int to, nxt;
}edge[MAX_N];
void addEdge(int u, int v) {
edge[tot].nxt = head[u];
edge[tot].to = v;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
head[v] = tot++;
}
int top[MAX_N];
int father[MAX_N];
int dep[MAX_N];
int sz[MAX_N];
int son[MAX_N];
int dfn[MAX_N];
int sa[MAX_N];
int dfncnt = 0;
void dfs1(int u, int from, int d) {
sz[u] = 1;
father[u] = from;
dep[u] = d;
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == from) continue;
dfs1(v, u, d+1);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) {
son[u] = v;
}
}
}
void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++dfncnt;
sa[dfncnt] = u;
if (son[u]) dfs2(son[u], tp);
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == son[u] || v == father[u]) continue;
dfs2(v, v);
}
}
struct Seg {
struct Tr {
int k, lazy, len;
}tr[MAX_N];
void push_up(int rt) {
tr[rt].k = tr[rt<<1].k ^ tr[rt<<1|1].k;
}
void calc(int rt, int lazy) {
if (lazy == -1) return;
tr[rt].k = lazy&tr[rt].len;
tr[rt].lazy = lazy;
}
void push_down(int rt) {
if (tr[rt].lazy == - 1) return;
int ls = rt << 1;
int rs = ls|1;
int& lazy = tr[rt].lazy;
calc(ls, lazy);
calc(rs, lazy);
tr[rt].lazy = -1;
}
void build(int rt, int l, int r) {
tr[rt].len = r - l + 1;
tr[rt].lazy = -1;
if (l == r) {
tr[rt].k = arr[sa[l]]&1;
return;
}
int mid = l + ((r-l)>>1);
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
push_up(rt);
}
void update(int rt, int l, int r, int x, int y, int k) {
if (x <= l && r <= y) {
calc(rt, k);
return;
}
push_down(rt);
int mid = l + ((r-l)>>1);
if (x <= mid) update(rt<<1, l, mid, x, y, k);
if (y > mid) update(rt<<1|1, mid+1, r, x, y, k);
push_up(rt);
}
int query(int rt, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return tr[rt].k;
}
push_down(rt);
int mid = l + ((r-l)>>1);
if (y <= mid) return query(rt<<1, l, mid, x, y);
if (x > mid) return query(rt<<1|1, mid+1, r, x, y);
return query(rt<<1, l, mid, x, y) ^ query(rt<<1|1, mid+1, r, x, y);
}
}bit[33];
void change(int x, int y, int id, int k) {
while (top[x] != top[y]) {
if (dep[top[x]] >= dep[top[y]]) {
bit[id].update(1, 1, N, dfn[top[x]], dfn[x], k);
x = father[top[x]];
} else {
bit[id].update(1, 1, N, dfn[top[y]], dfn[y], k);
y = father[top[y]];
}
}
if (dep[x] > dep[y]) {
bit[id].update(1, 1, N, dfn[y], dfn[x], k);
} else {
bit[id].update(1, 1, N, dfn[x], dfn[y], k);
}
}
int queryBit(int x, int y, int id) {
int res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] >= dep[top[y]]) {
res ^= bit[id].query(1, 1, N, dfn[top[x]], dfn[x]);
x = father[top[x]];
} else {
res ^= bit[id].query(1, 1, N, dfn[top[y]], dfn[y]);
y = father[top[y]];
}
}
if (dep[x] >= dep[y]) {
res ^= bit[id].query(1, 1, N, dfn[y], dfn[x]);
} else {
res ^= bit[id].query(1, 1, N, dfn[x], dfn[y]);
}
return res;
}
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void solve(){
init();
sc("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
sc("%d", &arr[i]);
}
int u, v;
for (int i = 2; i <= N; ++i) {
sc("%d%d", &u, &v);
addEdge(u, v);
}
dfs1(1, 0, 1);
dfs2(1, 1);
for (int i = 0; i <= 31; ++i) {
if (i) for (int j = 1; j <= N; ++j) arr[j] >>= 1;
bit[i].build(1, 1, N);
}
int opt, s, t, j;
for (int i = 1; i <= M; ++i) {
sc("%d%d%d", &opt, &s, &t);
if (opt == 1) {
for (j = 0; j <= 31; ++j) {
if (t>>j&1) {
change(1, s, j, 1);
}
}
} else if (opt == 2) {
for (j = 0; j <= 31; ++j) {
if (t>>j&1);
else {
change(1, s, j, 0);
}
}
} else {
for (j = 0; j <= 31; ++j) {
if (queryBit(1, s, j) ^ (t>>j&1)) {
puts("YES");
break;
}
}
if (j == 32) puts("NO");
}
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}