forked from indy256/codelibrary
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHeavyLight.java
113 lines (97 loc) · 3.18 KB
/
HeavyLight.java
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
package structures;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
// Heavy-light decomposition with path queries. Query complexity is O(log^2(n)).
// Based on the code from http://codeforces.com/blog/entry/22072
public class HeavyLight {
List<Integer>[] tree;
boolean valuesOnVertices; // true - values on vertices, false - values on edges
public SegmentTree segmentTree;
int[] parent;
int[] depth;
int[] pathRoot;
int[] in;
int time;
public HeavyLight(List<Integer>[] tree, boolean valuesOnVertices) {
this.tree = tree;
this.valuesOnVertices = valuesOnVertices;
int n = tree.length;
segmentTree = new SegmentTree(n);
parent = new int[n];
depth = new int[n];
pathRoot = new int[n];
in = new int[n];
parent[0] = -1;
dfs1(0);
dfs2(0);
}
int dfs1(int u) {
int size = 1;
int maxSubtree = 0;
for (int i = 0; i < tree[u].size(); i++) {
int v = tree[u].get(i);
if (v == parent[u])
continue;
parent[v] = u;
depth[v] = depth[u] + 1;
int subtree = dfs1(v);
if (maxSubtree < subtree) {
maxSubtree = subtree;
tree[u].set(i, tree[u].set(0, v));
}
size += subtree;
}
return size;
}
void dfs2(int u) {
in[u] = time++;
for (int v : tree[u]) {
if (v == parent[u])
continue;
pathRoot[v] = v == tree[u].get(0) ? pathRoot[u] : v;
dfs2(v);
}
}
public SegmentTree.Node get(int u, int v) {
SegmentTree.Node[] res = {new SegmentTree.Node()};
processPath(u, v, (a, b) -> res[0] = SegmentTree.unite(res[0], segmentTree.get(a, b)));
return res[0];
}
public void modify(int u, int v, long delta) {
processPath(u, v, (a, b) -> segmentTree.modify(a, b, delta));
}
void processPath(int u, int v, BiConsumer<Integer, Integer> op) {
for (; pathRoot[u] != pathRoot[v]; v = parent[pathRoot[v]]) {
if (depth[pathRoot[u]] > depth[pathRoot[v]]) {
int t = u;
u = v;
v = t;
}
op.accept(in[pathRoot[v]], in[v]);
}
if (u != v || valuesOnVertices)
op.accept(Math.min(in[u], in[v]) + (valuesOnVertices ? 0 : 1), Math.max(in[u], in[v]));
}
// Usage example
public static void main(String[] args) {
List<Integer>[] tree = Stream.generate(ArrayList::new).limit(5).toArray(List[] ::new);
tree[0].add(1);
tree[1].add(0);
tree[0].add(2);
tree[2].add(0);
tree[1].add(3);
tree[3].add(1);
tree[1].add(4);
tree[4].add(1);
HeavyLight hlV = new HeavyLight(tree, true);
hlV.modify(3, 2, 1);
hlV.modify(1, 0, -1);
System.out.println(1 == hlV.get(4, 2).sum);
HeavyLight hlE = new HeavyLight(tree, false);
hlE.modify(3, 2, 1);
hlE.modify(1, 0, -1);
System.out.println(1 == hlE.get(4, 2).sum);
}
}