-
Notifications
You must be signed in to change notification settings - Fork 31
/
CentroidDecomposition.go
117 lines (104 loc) · 2.78 KB
/
CentroidDecomposition.go
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
// https://ei1333.github.io/library/graph/tree/centroid-decomposition.hpp
// https://ei1333.github.io/library/test/verify/aoj-3139.test.cpp
// https://ei1333.github.io/library/test/verify/yosupo-frequency-table-of-tree-distance.test.cpp
// https://ei1333.github.io/library/test/verify/yukicoder-1002.test.cpp
// 重心互相连接形成的有根树, 可以想象把树拎起来, 重心在树的中心,连接着各个子树的重心...
// 3 (重)
// / | \
// (重)1 0 2 (重)
// / \ |
// 4 5 6
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// https://atcoder.jp/contests/abc291/tasks/abc291_h
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var n int
fmt.Fscan(in, &n)
g := make([][]Edge, n)
for i := 0; i < n-1; i++ {
var u, v int
fmt.Fscan(in, &u, &v)
u, v = u-1, v-1
g[u] = append(g[u], Edge{to: v})
g[v] = append(g[v], Edge{to: u})
}
centTree, root := CentroidDecomposition(g)
parents := make([]int, n)
for i := 0; i < n; i++ {
parents[i] = -1
}
var dfs func(int)
dfs = func(cur int) {
for _, to := range centTree[cur] {
parents[to] = cur
dfs(to)
}
}
dfs(root)
for _, v := range parents {
if v == -1 {
fmt.Fprint(out, -1, " ")
} else {
fmt.Fprint(out, v+1, " ")
}
}
}
type Edge = struct{ to, weight int }
// 树的重心分解, 返回点分树和点分树的根
//
// !tree: `无向`树的邻接表.
// centTree: 重心互相连接形成的有根树, 可以想象把树拎起来, 重心在树的中心,连接着各个子树的重心...
// root: 点分树的根
func CentroidDecomposition(tree [][]Edge) (centTree [][]int, root int) {
n := len(tree)
subSize := make([]int, n)
removed := make([]bool, n)
centTree = make([][]int, n)
var getSize func(cur, parent int) int
var getCentroid func(cur, parent, mid int) int
var build func(cur int) int
getSize = func(cur, parent int) int {
subSize[cur] = 1
for _, e := range tree[cur] {
next := e.to
if next == parent || removed[next] {
continue
}
subSize[cur] += getSize(next, cur)
}
return subSize[cur]
}
getCentroid = func(cur, parent, mid int) int {
for _, e := range tree[cur] {
next := e.to
if next == parent || removed[next] {
continue
}
if subSize[next] > mid {
return getCentroid(next, cur, mid)
}
}
return cur
}
build = func(cur int) int {
centroid := getCentroid(cur, -1, getSize(cur, -1)/2)
removed[centroid] = true
for _, e := range tree[centroid] {
next := e.to
if !removed[next] {
centTree[centroid] = append(centTree[centroid], build(next))
}
}
removed[centroid] = false
return centroid
}
root = build(0)
return
}