/
HLD (Heavy Light Decomposition).cpp
138 lines (125 loc) · 2.93 KB
/
HLD (Heavy Light Decomposition).cpp
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* Operations:
* 1 u x : set val[u] = x
* 2 u v : sum of val[i] in (u,v) path
*/
#define ll long long
#define pb push_back
const ll sz = 3e4 + 10;
vector <ll> g[sz];
ll sub[sz], in[sz], out[sz], head[sz], tim;
ll par[sz], tr[4*sz];
void dfs_siz(ll u, ll p)
{
sub[u] = 1, par[u] = p;
for(ll &v : g[u]) {
if(v == p)
continue;
dfs_siz(v, u);
sub[u] += sub[v];
if(sub[v] > sub[ g[u][0] ])
swap(v, g[u][0]);
}
}
/* DFS for Heavy-Light Decomposition
* head[u] = Head of the chain of node u
* Operations can be performed in [in[head[u]],in[u]] range.
* As DFS-time is used, [in[u],out[u]] range can be used
for performing operations on the subtree of node u.
*/
void dfs_hld(ll u, ll p)
{
if(p == -1) head[u] = u; // root
in[u] = ++tim;
for(ll &v : g[u]) {
if(v == p)
continue;
head[v] = (v==g[u][0]? head[u] : v);
dfs_hld(v, u);
}
out[u] = tim;
}
// Typical Segment Tree on [1, tim] range
void build(ll lo, ll hi, ll node)
{
if(lo == hi) {
tr[node] = 0;
return;
}
ll mid = lo+hi>>1, lft=node<<1, rgt=lft|1;
build(lo, mid, lft);
build(mid+1, hi, rgt);
tr[node] = 0;
}
void update(ll lo, ll hi, ll idx, ll v, ll node)
{
if(lo > idx || hi < idx)
return;
if(lo == hi) {
tr[node] = v;
return;
}
ll mid = lo+hi>>1, lft=node<<1, rgt=lft|1;
update(lo, mid, idx, v, lft);
update(mid+1, hi, idx, v, rgt);
tr[node] = tr[lft] + tr[rgt];
}
ll query(ll lo, ll hi, ll l, ll r, ll node)
{
if(lo > r || hi < l)
return 0;
if(lo >= l && hi <= r)
return tr[node];
ll mid = lo+hi>>1, lft=node<<1, rgt=lft|1;
return query(lo, mid, l, r, lft)
+ query(mid+1, hi, l, r, rgt);
}
// Segment Tree Ends
inline bool isAncestor(int p,int u){
return in[p]<=in[u]&&out[p]>=out[u];
}
void upd_val(ll u, ll val) {
update(1, tim, in[u], val, 1);
}
ll query_path(ll u, ll v)
{
ll ret = 0;
while(!isAncestor(head[u],v)) {
ret += query(1,tim, in[head[u]], in[u], 1);
u=par[head[u]];
}
swap(u,v);
while(!isAncestor(head[u],v)) {
ret += query(1,tim, in[head[u]], in[u], 1);
u=par[head[u]];
}
if(in[v]<in[u])swap(u,v);
ret += query(1,tim, in[u], in[v], 1); // u is LCA
return ret;
}
void clr(ll n) {
tim = 0;
for(ll i=1; i <=n; i++)
g[i].clear();
}
int main()
{
ll t, n, q, u, v, op, root=1;
cin >> t;
while(t--) {
scanf("%lld", &n); clr(n);
for(ll i=1; i<n; i++) {
scanf("%lld %lld", &u, &v);
g[u].pb(v), g[v].pb(u);
}
dfs_siz(root, -1);
dfs_hld(root, -1);
build(1, tim, 1);
scanf("%lld", &q);
while(q--) {
scanf("%lld %lld %lld", &op, &u, &v);
if(op == 1) upd_val(u, v);
else printf("%lld\n", query_path(u, v));
}
}
return 0;
}