結果
問題 | No.1418 Sum of Sum of Subtree Size |
ユーザー | 草苺奶昔 |
提出日時 | 2023-03-15 23:34:26 |
言語 | Go (1.22.1) |
結果 |
AC
|
実行時間 | 243 ms / 2,000 ms |
コード長 | 6,632 bytes |
コンパイル時間 | 14,576 ms |
コンパイル使用メモリ | 236,864 KB |
実行使用メモリ | 44,928 KB |
最終ジャッジ日時 | 2024-09-18 08:58:00 |
合計ジャッジ時間 | 18,417 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,816 KB |
testcase_01 | AC | 1 ms
6,816 KB |
testcase_02 | AC | 2 ms
6,944 KB |
testcase_03 | AC | 234 ms
27,884 KB |
testcase_04 | AC | 240 ms
27,776 KB |
testcase_05 | AC | 243 ms
27,648 KB |
testcase_06 | AC | 243 ms
27,776 KB |
testcase_07 | AC | 238 ms
27,776 KB |
testcase_08 | AC | 154 ms
18,944 KB |
testcase_09 | AC | 62 ms
9,728 KB |
testcase_10 | AC | 68 ms
10,624 KB |
testcase_11 | AC | 35 ms
6,784 KB |
testcase_12 | AC | 111 ms
14,976 KB |
testcase_13 | AC | 130 ms
16,640 KB |
testcase_14 | AC | 141 ms
17,024 KB |
testcase_15 | AC | 103 ms
14,720 KB |
testcase_16 | AC | 12 ms
5,376 KB |
testcase_17 | AC | 11 ms
5,376 KB |
testcase_18 | AC | 221 ms
24,832 KB |
testcase_19 | AC | 31 ms
6,528 KB |
testcase_20 | AC | 5 ms
5,376 KB |
testcase_21 | AC | 98 ms
14,464 KB |
testcase_22 | AC | 83 ms
12,416 KB |
testcase_23 | AC | 6 ms
5,376 KB |
testcase_24 | AC | 7 ms
5,376 KB |
testcase_25 | AC | 5 ms
5,376 KB |
testcase_26 | AC | 6 ms
5,376 KB |
testcase_27 | AC | 2 ms
5,376 KB |
testcase_28 | AC | 3 ms
5,376 KB |
testcase_29 | AC | 9 ms
5,376 KB |
testcase_30 | AC | 7 ms
5,376 KB |
testcase_31 | AC | 5 ms
5,376 KB |
testcase_32 | AC | 5 ms
5,376 KB |
testcase_33 | AC | 44 ms
12,032 KB |
testcase_34 | AC | 227 ms
44,928 KB |
testcase_35 | AC | 90 ms
21,376 KB |
testcase_36 | AC | 17 ms
5,504 KB |
testcase_37 | AC | 164 ms
27,392 KB |
testcase_38 | AC | 146 ms
26,240 KB |
testcase_39 | AC | 2 ms
5,376 KB |
testcase_40 | AC | 1 ms
5,376 KB |
testcase_41 | AC | 1 ms
5,376 KB |
testcase_42 | AC | 1 ms
5,376 KB |
testcase_43 | AC | 1 ms
5,376 KB |
ソースコード
package main import ( "bufio" "fmt" "os" ) func main() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n int fmt.Fscan(in, &n) R := NewRerootingEdge(n) for i := 0; i < n-1; i++ { var a, b int fmt.Fscan(in, &a, &b) a, b = a-1, b-1 R.AddEdge(a, b, 1) } dp := R.ReRooting( func() E { return E{0, 0} }, func(a, b E) E { return E{a[0] + b[0], a[1] + b[1]} }, func(a E, v int) E { return E{a[0] + 1, a[1] + a[0] + 1} }, func(a E, edge [2]int) E { return a }, ) res := 0 for _, v := range dp { res += v[1] } fmt.Fprintln(out, res) } type E = [2]int type ReRootingEdge struct { tree *_T dp1 []E // 边 pv 的子树v的dp值 dp2 []E // 边 pv 的子树p的dp值 dp []E // 所有顶点v的子树dp值 } func NewRerootingEdge(n int) *ReRootingEdge { return &ReRootingEdge{tree: _NT(n)} } func (rr *ReRootingEdge) AddEdge(from, to, weight int) { rr.tree.AddEdge(from, to, weight) } // !root 作为根节点时, 子树 v 的 dp 值 func (rr *ReRootingEdge) Get(root, v int) E { if root == v { return rr.dp[v] } if !rr.tree.IsInSubtree(root, v) { return rr.dp1[v] } w := rr.tree.Jump(v, root, 1) return rr.dp2[w] } func (rr *ReRootingEdge) ReRooting( e func() E, op func(a, b E) E, fev func(dp E, v int) E, fve func(dp E, edge [2]int /*next, weight*/) E, ) []E { rr.tree.Build(0) unit := e() N := len(rr.tree.Tree) dp1, dp2, dp := make([]E, N), make([]E, N), make([]E, N) for i := 0; i < N; i++ { dp1[i] = unit dp2[i] = unit dp[i] = unit } V := rr.tree.idToNode par := rr.tree.Parent for i := N - 1; i >= 0; i-- { v := V[i] ch := rr.tree.CollectChild(v) n := len(ch) x1, x2 := make([]E, n+1), make([]E, n+1) for i := range x1 { x1[i] = unit x2[i] = unit } for i := 0; i < n; i++ { x1[i+1] = op(x1[i], dp2[ch[i]]) } for i := n - 1; i >= 0; i-- { x2[i] = op(dp2[ch[i]], x2[i+1]) } for i := 0; i < n; i++ { dp2[ch[i]] = op(x1[i], x2[i+1]) } dp[v] = x2[0] dp1[v] = fev(dp[v], v) for _, e := range rr.tree.Tree[v] { to := e[0] if to == par[v] { dp2[v] = fve(dp1[v], e) } } } v := V[0] dp[v] = fev(dp[v], v) for _, e := range rr.tree.Tree[v] { to := e[0] dp2[to] = fev(dp2[to], v) } for i := 0; i < N; i++ { v := V[i] for _, e := range rr.tree.Tree[v] { to := e[0] if to == par[v] { continue } x := fve(dp2[to], e) for _, f := range rr.tree.Tree[to] { to := f[0] if to == par[to] { continue } dp2[to] = op(dp2[to], x) dp2[to] = fev(dp2[to], to) } x = op(dp[to], x) dp[to] = fev(x, to) } } rr.dp1, rr.dp2, rr.dp = dp1, dp2, dp return dp } type _T struct { Tree [][][2]int // (next, weight) Depth []int Parent []int LID, RID []int // 欧拉序[in,out) idToNode []int top, heavySon []int timer int } func _NT(n int) *_T { tree := make([][][2]int, n) lid := make([]int, n) rid := make([]int, n) idToNode := make([]int, n) top := make([]int, n) // 所处轻/重链的顶点(深度最小),轻链的顶点为自身 depth := make([]int, n) // 深度 parent := make([]int, n) // 父结点 heavySon := make([]int, n) // 重儿子 for i := range parent { parent[i] = -1 } return &_T{ Tree: tree, Depth: depth, Parent: parent, LID: lid, RID: rid, idToNode: idToNode, top: top, heavySon: heavySon, } } // 添加无向边 u-v, 边权为w. func (tree *_T) AddEdge(u, v, w int) { tree.Tree[u] = append(tree.Tree[u], [2]int{v, w}) tree.Tree[v] = append(tree.Tree[v], [2]int{u, w}) } // 添加有向边 u->v, 边权为w. func (tree *_T) AddDirectedEdge(u, v, w int) { tree.Tree[u] = append(tree.Tree[u], [2]int{v, w}) } // root:0-based // 当root设为-1时,会从0开始遍历未访问过的连通分量 func (tree *_T) Build(root int) { if root != -1 { tree.build(root, -1, 0) tree.markTop(root, root) } else { for i := 0; i < len(tree.Tree); i++ { if tree.Parent[i] == -1 { tree.build(i, -1, 0) tree.markTop(i, i) } } } } func (tree *_T) LCA(u, v int) int { for { if tree.LID[u] > tree.LID[v] { u, v = v, u } if tree.top[u] == tree.top[v] { return u } v = tree.Parent[tree.top[v]] } } // k: 0-based // 如果不存在第k个祖先,返回-1 func (tree *_T) KthAncestor(root, k int) int { if k > tree.Depth[root] { return -1 } for { u := tree.top[root] if tree.LID[root]-k >= tree.LID[u] { return tree.idToNode[tree.LID[root]-k] } k -= tree.LID[root] - tree.LID[u] + 1 root = tree.Parent[u] } } // 从 from 节点跳向 to 节点,跳过 step 个节点(0-indexed) // 返回跳到的节点,如果不存在这样的节点,返回-1 func (tree *_T) Jump(from, to, step int) int { if step == 1 { if from == to { return -1 } if tree.IsInSubtree(to, from) { return tree.KthAncestor(to, tree.Depth[to]-tree.Depth[from]-1) } return tree.Parent[from] } c := tree.LCA(from, to) dac := tree.Depth[from] - tree.Depth[c] dbc := tree.Depth[to] - tree.Depth[c] if step > dac+dbc { return -1 } if step <= dac { return tree.KthAncestor(from, step) } return tree.KthAncestor(to, dac+dbc-step) } func (tree *_T) CollectChild(root int) []int { res := []int{} for _, e := range tree.Tree[root] { next := e[0] if next != tree.Parent[root] { res = append(res, next) } } return res } func (tree *_T) SubtreeSize(u int) int { return tree.RID[u] - tree.LID[u] } // child 是否在 root 的子树中 (child和root不能相等) func (tree *_T) IsInSubtree(child, root int) bool { return tree.LID[root] <= tree.LID[child] && tree.LID[child] < tree.RID[root] } func (tree *_T) build(cur, pre, dep int) int { subSize, heavySize, heavySon := 1, 0, -1 for _, e := range tree.Tree[cur] { next := e[0] if next != pre { nextSize := tree.build(next, cur, dep+1) subSize += nextSize if nextSize > heavySize { heavySize, heavySon = nextSize, next } } } tree.Depth[cur] = dep tree.heavySon[cur] = heavySon tree.Parent[cur] = pre return subSize } func (tree *_T) markTop(cur, top int) { tree.top[cur] = top tree.LID[cur] = tree.timer tree.idToNode[tree.timer] = cur tree.timer++ if tree.heavySon[cur] != -1 { tree.markTop(tree.heavySon[cur], top) for _, e := range tree.Tree[cur] { next := e[0] if next != tree.heavySon[cur] && next != tree.Parent[cur] { tree.markTop(next, next) } } } tree.RID[cur] = tree.timer } func min(a, b int) int { if a < b { return a } return b } func max(a, b int) int { if a > b { return a } return b }