题目描述
魔法森林里有一颗大树,下面经常有小孩召开法。
大树可以看做一个有 n n n 个节点, n − 1 n - 1 n−1 条边的无向连通图。大树的每个节点都有若干瓶矿泉水,初始第 i i i 个节点有 a i a_i ai 瓶矿泉水。
麦杰斯住在大树顶端,有一天他想改造一下大树,方便他巨大多喝水之后可以垃圾分类矿泉水瓶。
麦杰斯喜欢二进制运算,所以他会有以下三种操作:
麦杰斯共有 m m m 次操作,他希望你在每次 3 3 3 操作后告诉他答案。
输入格式
第一行两个正整数 n , m n,m n,m ,分别表示树的节点个数和麦杰斯的询问个数。
第二行到第 n n n 行,每行两个整数表示有一条连接这两个节点的边。
第 n + 1 n + 1 n+1 行 n n n 个整数,第 i i i 个整数表示初始第 i i i 个节点上的矿泉水数量。
第 n + 2 n + 2 n+2 行到第 n + m + 1 n + m + 1 n+m+1 行,每行先读入一个整数 o p t opt opt 表示操作类型。
如果 o p t = 1 opt = 1 opt=1 或 3 3 3 ,接下来读入一个整数 x x x 表示麦杰斯操作的节点标号。
否则接下来读入两个整数 x , v x, v x,v 表示麦杰斯操作的节点标号和他喝的水的数量。
输出格式
对于每一个 3 3 3 操作,输出一行一个整数表示答案。
输入输出样例
输入 #1
3 2
1 2
2 3
1 1 4
1 1
3 2
输出 #1
5
说明/提示
Idea:dangxingyu,Solution:dangxingyu,Code:dangxingyu,Data:dangxingyu
对于 30 % 30\% 30% 的数据,满足 n ≤ 1 0 3 n \le 10^3 n≤103, m ≤ 1 0 3 m\le 10^3 m≤103。
对于 60 % 60\% 60% 的数据,满足 n ≤ 1 0 5 n \le 10^5 n≤105, m ≤ 1 0 5 m \le 10^5 m≤105。
对于另外 10 % 10\% 10% 的数据,存在一个点满足所有点到该节点的距离 ≤ 1 \le 1 ≤1。
对于 100 % 100\% 100% 的数据,满足 1 ≤ n ≤ 5 × 1 0 5 1\le n \le 5\times 10^5 1≤n≤5×105, 1 ≤ m ≤ 5 × 1 0 5 1\le m \le 5\times 10^5 1≤m≤5×105, 0 ≤ a i ≤ 1 0 5 0\le a_i \le 10^5 0≤ai≤105, 1 ≤ x ≤ n 1 \le x \le n 1≤x≤n, o p t ∈ { 1 , 2 , 3 } opt\in\{1,2,3\} opt∈{1,2,3}。
保证任意时刻每个节点的矿泉水数非负。
使用 01 − t r i e 01-trie 01−trie维护每个节点的所有子节点的异或和。
设 f a [ x ] fa[x] fa[x]表示节点 x x x的父节点; l z y [ x ] lzy[x] lzy[x]表示节点 x x x操作 1 1 1进行的次数; v [ x ] v[x] v[x]表示除去 f a [ x ] fa[x] fa[x]通过操作 1 1 1对 x x x进行修改外 x x x的当前值。
#include
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector
#define pii pair
#define mii unordered_map
#define msi unordered_map
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;
inline int qr() {
int f = 0, fu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')fu = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
f = (f << 3) + (f << 1) + c - 48;
c = getchar();
}
return f * fu;
}
const int N = 5e5 + 10;
struct Trie {
const int H = 18;
int ch[N * 25][2], w[N * 25], xorv[N * 25], rt[N];
int tot = 0;
inline int build() {
++tot;
ch[tot][0] = ch[tot][1] = w[tot] = xorv[tot] = 0;
return tot;
}
inline void update(int p) {
w[p] = xorv[p] = 0;
if (ch[p][0]) {
w[p] += w[ch[p][0]];
xorv[p] ^= xorv[ch[p][0]] << 1;
}
if (ch[p][1]) {
w[p] += w[ch[p][1]];
xorv[p] ^= (xorv[ch[p][1]] << 1) | w[ch[p][1]];
}
w[p] &= 1;
}
void insert(int &p, int d, int x) {
if (!p)p = build();
if (d > H) {
w[p]++;
return;
}
insert(ch[p][x & 1], d + 1, x >> 1);
update(p);
}
void erase(int p, int d, int x) {
if (d > H) {
w[p]--;
return;
}
erase(ch[p][x & 1], d + 1, x >> 1);
update(p);
}
void addall(int p) {
swap(ch[p][0], ch[p][1]);
if (ch[p][0])addall(ch[p][0]);
update(p);
}
int merge(int p, int q) {
if (!p)return q;
if (!q)return p;
w[p] = w[p] + w[q] & 1, xorv[p] ^= xorv[q];
ch[p][0] = merge(ch[p][0], ch[q][0]);
ch[p][1] = merge(ch[p][1], ch[q][1]);
return p;
}
} tr;
int head[N], ver[N << 1], Next[N << 1], tot;
int fa[N], v[N], lzy[N], n, m;
inline void add(int x, int y) {
ver[++tot] = y;
Next[tot] = head[x];
head[x] = tot;
}
inline int get(int x) {
return v[x] + lzy[fa[x]];
}
void dfs(int x, int f) {
fa[x] = f;
reps(x) {
int y = ver[i];
if (y == f)continue;
dfs(y, x);
}
}
int main() {
n = qr(), m = qr();
repi(i, 1, n - 1) {
int x = qr(), y = qr();
add(x, y), add(y, x);
}
dfs(1, 0);
repi(i, 1, n) {
v[i] = qr();
if (fa[i])tr.insert(tr.rt[fa[i]], 0, v[i]);
}
while (m--) {
int op = qr(), x = qr();
if (op == 1) {
lzy[x]++;
if (fa[fa[x]])tr.erase(tr.rt[fa[fa[x]]], 0, get(fa[x]));
if (fa[x])v[fa[x]]++;
if (fa[fa[x]])tr.insert(tr.rt[fa[fa[x]]], 0, get(fa[x]));
tr.addall(tr.rt[x]);
} else if (op == 2) {
if (fa[x])tr.erase(tr.rt[fa[x]], 0, get(x));
v[x] -= qr();
if (fa[x])tr.insert(tr.rt[fa[x]], 0, get(x));
} else
pi(tr.xorv[tr.rt[x]] ^ get(fa[x]));
}
return 0;
}