0%

CF383C Propagating tree

传送门

Solution

一棵子树中的所有点的 dfs 序必定连续,因此先 dfs 求出每个点的 dfs 序和深度,以及该子树的点的 dfs 序的左右边界。

然后就可以以 dfs 序为序列,建立线段树维护。当 TiT_i 是线段树的非叶节点时,其充当 lazy tag 的作用。从 TiT_i pushdown 到叶节点时,根据叶节点对应树中节点的深度奇偶性,决定将 TiT_i 加或减到叶节点上。若 pushdown 到非叶节点,则该子节点直接加上 TiT_i 并将 TiT_i 清零。

根据上述规则,执行操作 1 时,根据子树根节点的深度奇偶性决定将 valval 还是 val-val 加到线段树对应区间上。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <bits/stdc++.h>
#define ls k<<1
#define rs k<<1|1
using namespace std;
typedef long long ll;

const ll N = 2e5 + 10;

ll n, m, L[N], dfn_cnt, a[N], R[N], siz[N], dep[N], mp[N];
struct Node {
ll l, r, sum, siz;
} T[N << 2];
vector<ll> g[N];

void dfs(ll u, ll pre)
{
dep[u] = dep[pre] + 1;
L[u] = ++dfn_cnt;
siz[u] = 1;
for (ll v : g[u]) {
if (v == pre) continue;
dfs(v, u);
siz[u] += siz[v];
}
R[u] = dfn_cnt;
}

void build(ll k, ll l, ll r)
{
T[k].l = l; T[k].r = r; T[k].siz = r - l + 1;
if (l == r) {
T[k].sum = a[mp[l]];
return;
}
ll mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}

void push_down(ll k)
{
if (T[ls].siz == 1) {
if (dep[mp[T[ls].l]] & 1)
T[ls].sum += T[k].sum;
else
T[ls].sum -= T[k].sum;
} else
T[ls].sum += T[k].sum;
if (T[rs].siz == 1) {
if (dep[mp[T[rs].l]] & 1)
T[rs].sum += T[k].sum;
else
T[rs].sum -= T[k].sum;
} else
T[rs].sum += T[k].sum;
T[k].sum = 0;
}

void modify(ll k, ll x, ll y, ll z)
{
if (x <= T[k].l && T[k].r <= y) {
if (T[k].siz > 1)
T[k].sum += z;
else {
if (dep[mp[T[k].l]] & 1)
T[k].sum += z;
else
T[k].sum -= z;
}
return;
}
ll mid = (T[k].l + T[k].r) >> 1;
push_down(k);
if (x <= mid) modify(ls, x, y, z);
if (mid < y) modify(rs, x, y, z);
}

ll query(ll k, ll x)
{
if (T[k].l == T[k].r && T[k].l == x)
return T[k].sum;
push_down(k);
ll mid = (T[k].l + T[k].r) >> 1;
if (x <= mid) return query(ls, x);
else return query(rs, x);
}

int main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i < n; i++) {
ll u, v;
scanf("%lld%lld", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
mp[L[i]] = i;
build(1, 1, n);
while (m--) {
ll opt, x, y;
scanf("%lld%lld", &opt, &x);
if (opt == 1) {
scanf("%lld", &y);
if (dep[x] & 1)
modify(1, L[x], R[x], y);
else
modify(1, L[x], R[x], -y);
} else
printf("%lld\n", query(1, L[x]));
}
return 0;
}