一、题目链接
二、题目大意
给一个 n n n 个点且以 1 1 1 号点为根的树,第 i i i 个点的点权为 a [ i ] a[i] a[i], m m m 次操作,操作有 3 3 3 种:
1. 1. 1. 给出 s s s 和 t t t,要求把从 1 1 1 到 s s s 路径上的点的点权 ∣ = t |= t ∣=t.
2. 2. 2. 给出 s s s 和 t t t,要求把从 1 1 1 到 s s s 路径上的点的点权 & = t \&= t &=t.
3. 3. 3. 给出 s s s 和 t t t,要求把从 1 1 1 到 s s s 路径上的点与另外一个点权为 t t t 的新点做 nim 博弈,问先手是否必胜.
1 ≤ n , m , s ≤ 1 0 5 1 \leq n, m, s \leq 10^5 1≤n,m,s≤105.
1 ≤ a [ i ] , t ≤ 1 0 9 1 \leq a[i], t \leq 10^9 1≤a[i],t≤109.
o p ∈ { 1 , 2 , 3 } op \in \{1,2,3\} op∈{1,2,3}.
三、分析
显然重链剖分,再用线段树维护区间异或值,用双重懒惰标记处理一下前两种操作.
(以后这么长的代码还是得丢给队友写
四、代码实现
#include <bits/stdc++.h>
using namespace std;
const int M = (int)1e5;
const int N = (int)29;
int n, m;
int cnt, head[M + 5];
struct enode
{
int v, nx;
} Edge[M * 2 + 5];
int a[M + 5];
int fa[M + 5];
int sz[M + 5];
int dep[M + 5];
int son[M + 5];
int top[M + 5];
int rnk[M + 5];
int dfn[M + 5], dfnCnt;
void init()
{
cnt = 0;
for(int i = 1; i <= n; ++i)
{
head[i] = -1;
}
}
void add(int u, int v)
{
Edge[cnt].v = v;
Edge[cnt].nx = head[u];
head[u] = cnt++;
}
void dfs1(int u, int fa)
{
::fa[u] = fa, sz[u] = 1, son[u] = -1;
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v;
if(v == fa) continue;
dep[v] = dep[u] + 1;
dfs1(v, u);
sz[u] += sz[v];
if(son[u] == -1 || sz[son[u]] < sz[v]) son[u] = v;
}
}
void dfs2(int u, int tp)
{
top[u] = tp, dfn[u] = ++dfnCnt, rnk[dfnCnt] = u;
if(son[u] == -1) return;
dfs2(son[u], tp);
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
struct tnode
{
bool c[N + 1];
int l, r, lzOR, lzAND;
} tree[M * 4 + 5];
int msk = (1<<N+1) - 1;
inline int lc(int k) {return k<<1;}
inline int rc(int k) {return k<<1|1;}
inline void push_up(int k)
{
for(int i = 0; i <= N; ++i)
{
tree[k].c[i] = (tree[lc(k)].c[i] ^ tree[rc(k)].c[i]);
}
}
inline void push_down(int k)
{
if(tree[k].lzOR)
{
for(int i = 0; i <= N; ++i)
{
if(tree[k].lzOR>>i&1)
{
tree[lc(k)].c[i] = ((tree[lc(k)].r - tree[lc(k)].l + 1) & 1);
tree[rc(k)].c[i] = ((tree[rc(k)].r - tree[rc(k)].l + 1) & 1);
}
}
tree[lc(k)].lzOR |= tree[k].lzOR, tree[rc(k)].lzOR |= tree[k].lzOR;
tree[lc(k)].lzAND |= tree[k].lzOR, tree[rc(k)].lzAND |= tree[k].lzOR;
tree[k].lzOR = 0;
}
if(tree[k].lzAND != msk)
{
for(int i = 0; i <= N; ++i)
{
if(!(tree[k].lzAND>>i&1))
{
tree[lc(k)].c[i] = tree[rc(k)].c[i] = 0;
}
}
tree[lc(k)].lzAND &= tree[k].lzAND, tree[rc(k)].lzAND &= tree[k].lzAND, tree[k].lzAND = msk;
}
}
void build(int k, int l, int r)
{
tree[k].l = l, tree[k].r = r;
tree[k].lzOR = 0, tree[k].lzAND = msk;
if(l == r)
{
for(int i = 0; i <= N; ++i)
{
tree[k].c[i] = (a[rnk[l]]>>i&1);
}
return;
}
int mid = (l + r) >> 1;
build(lc(k), l, mid);
build(rc(k), mid + 1, r);
push_up(k);
}
void updateOR(int k, int a, int b, int c)
{
if(tree[k].l >= a && tree[k].r <= b)
{
for(int i = 0; i <= N; ++i)
{
if(c>>i&1)
{
tree[k].c[i] = ((tree[k].r - tree[k].l + 1) & 1);
tree[k].lzAND |= (1<<i);
}
}
tree[k].lzOR |= c;
return;
}
push_down(k);
int mid = (tree[k].l + tree[k].r) >> 1;
if(a <= mid) updateOR(lc(k), a, b, c);
if(mid < b) updateOR(rc(k), a, b, c);
push_up(k);
}
void OR(int u, int val)
{
while(top[u] != 1)
{
updateOR(1, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
updateOR(1, 1, dfn[u], val);
}
void updateAND(int k, int a, int b, int c)
{
if(tree[k].l >= a && tree[k].r <= b)
{
for(int i = 0; i <= N; ++i)
{
if(!(c>>i&1))
{
tree[k].c[i] = 0;
}
}
tree[k].lzAND &= c;
return;
}
push_down(k);
int mid = (tree[k].l + tree[k].r) >> 1;
if(a <= mid) updateAND(lc(k), a, b, c);
if(mid < b) updateAND(rc(k), a, b, c);
push_up(k);
}
void AND(int u, int val)
{
while(top[u] != 1)
{
updateAND(1, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
updateAND(1, 1, dfn[u], val);
}
int queryXOR(int k, int a, int b)
{
if(tree[k].l >= a && tree[k].r <= b)
{
int c = 0;
for(int i = 0; i <= N; ++i) if(tree[k].c[i]) c |= (1<<i);
return c;
}
push_down(k);
int mid = (tree[k].l + tree[k].r) >> 1, c = 0;
if(a <= mid) c ^= queryXOR(lc(k), a, b);
if(mid < b) c ^= queryXOR(rc(k), a, b);
push_up(k);
return c;
}
int XOR(int u, int val)
{
while(top[u] != 1)
{
val ^= queryXOR(1, dfn[top[u]], dfn[u]);
u = fa[top[u]];
}
val ^= queryXOR(1, 1, dfn[u]);
return val;
}
void work()
{
scanf("%d %d", &n, &m); init();
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 2, u, v; i <= n; ++i)
{
scanf("%d %d", &u, &v);
add(u, v), add(v, u);
}
dep[1] = 1; dfs1(1, 0); dfs2(1, 1);
build(1, 1, n);
for(int i = 1, op, s, t; i <= m; ++i)
{
scanf("%d %d %d", &op, &s, &t);
if(op == 1) OR(s, t);
else if(op == 2) AND(s, t);
else if(op == 3) puts(XOR(s, t) ? "YES" : "NO");
}
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("my.txt", "w", stdout);
work();
return 0;
}