結果
問題 | No.1976 Cut then Connect |
ユーザー | 草苺奶昔 |
提出日時 | 2023-03-16 10:36:35 |
言語 | Go (1.22.1) |
結果 |
AC
|
実行時間 | 236 ms / 2,000 ms |
コード長 | 4,104 bytes |
コンパイル時間 | 10,505 ms |
コンパイル使用メモリ | 239,800 KB |
実行使用メモリ | 38,784 KB |
最終ジャッジ日時 | 2024-11-24 12:20:29 |
合計ジャッジ時間 | 14,419 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 1 ms
5,248 KB |
testcase_02 | AC | 227 ms
36,992 KB |
testcase_03 | AC | 119 ms
24,848 KB |
testcase_04 | AC | 39 ms
10,880 KB |
testcase_05 | AC | 103 ms
22,400 KB |
testcase_06 | AC | 174 ms
29,952 KB |
testcase_07 | AC | 108 ms
23,040 KB |
testcase_08 | AC | 236 ms
38,784 KB |
testcase_09 | AC | 193 ms
33,024 KB |
testcase_10 | AC | 50 ms
11,904 KB |
testcase_11 | AC | 230 ms
38,272 KB |
testcase_12 | AC | 7 ms
5,248 KB |
testcase_13 | AC | 167 ms
29,952 KB |
testcase_14 | AC | 159 ms
28,416 KB |
testcase_15 | AC | 145 ms
29,080 KB |
testcase_16 | AC | 224 ms
35,200 KB |
testcase_17 | AC | 67 ms
16,128 KB |
testcase_18 | AC | 13 ms
5,248 KB |
testcase_19 | AC | 171 ms
29,696 KB |
testcase_20 | AC | 234 ms
38,656 KB |
testcase_21 | AC | 125 ms
26,112 KB |
testcase_22 | AC | 1 ms
5,248 KB |
testcase_23 | AC | 1 ms
5,248 KB |
testcase_24 | AC | 1 ms
5,248 KB |
testcase_25 | AC | 1 ms
5,248 KB |
testcase_26 | AC | 1 ms
5,248 KB |
testcase_27 | AC | 1 ms
5,248 KB |
testcase_28 | AC | 1 ms
5,248 KB |
testcase_29 | AC | 1 ms
5,248 KB |
testcase_30 | AC | 1 ms
5,248 KB |
testcase_31 | AC | 1 ms
5,248 KB |
testcase_32 | AC | 1 ms
5,248 KB |
ソースコード
package main import ( "bufio" "fmt" "os" "sort" ) func main() { // https://yukicoder.me/problems/no/1976 // No.1976 Cut then Connect-连边后树的最小直径 // 给定一棵树, 你可以做以下操作: // 从树的无向边中删除一条边, 使得图的连通分量数变为2 // 对于图的每个连通分量, 选择一个点, 用无向边将这两个点连接起来 // !问: 操作后的树的直径的最小值是多少? // 解: // 1. 固定每条删除的边时,求出每个连通分量的直径后可以求出新直径的最小值 // !此时答案为 max(x,y,ceil(x/2)+ceil(y/2)+1) 其中x,y为连通分量的直径 // 2. 对不同的边,考虑换根dp即可 in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n int fmt.Fscan(in, &n) R := NewRerootingSubTree(n) edges := make([][2]int, n-1) for i := 0; i < n-1; i++ { var a, b int fmt.Fscan(in, &a, &b) a, b = a-1, b-1 edges[i] = [2]int{a, b} R.AddEdge(a, b, Edge{from: a, to: b, cost: 1}) } // !E: (每个点处的直径,每个点到最远点的距离) R.ReRooting( func(root int) E { return E{0, 0} }, func(dp1, dp2 E) E { return E{max(max(dp1.dia, dp2.dia), dp1.dist+dp2.dist), max(dp1.dist, dp2.dist)} }, func(dp E, edge Edge) E { return E{dp.dia, dp.dist + 1} }, ) res := n for _, e := range edges { u, v := e[0], e[1] dia1, dia2 := R.SubTree(u, v).dia, R.SubTree(v, u).dia res = min(res, max(max(dia1, dia2), (dia1+1)/2+(dia2+1)/2+1)) } fmt.Fprintln(out, res) } type E = struct{ dia, dist int } type Edge = struct{ from, to, cost int } type ReRootingSubTree struct { G [][]Node ld, rd [][]E lp, rp []int e func(root int) E op func(dp1, dp2 E) E composition func(dp E, e Edge) E } type Node struct { to, rev int data Edge } func NewRerootingSubTree(n int) *ReRootingSubTree { res := &ReRootingSubTree{ G: make([][]Node, n), ld: make([][]E, n), rd: make([][]E, n), lp: make([]int, n), rp: make([]int, n), } return res } func (rr *ReRootingSubTree) AddEdge(u, v int, e Edge) { rr.G[u] = append(rr.G[u], Node{to: v, data: e}) rr.G[v] = append(rr.G[v], Node{to: u, data: e}) } func (rr *ReRootingSubTree) AddDirectedEdge(u, v int, e Edge) { rr.G[u] = append(rr.G[u], Node{to: v, data: e}) } func (rr *ReRootingSubTree) ReRooting( e func(root int) E, op func(dp1, dp2 E) E, compositionEdge func(dp E, e Edge) E, ) []E { rr.e = e rr.op = op rr.composition = compositionEdge n := len(rr.G) for i := 0; i < n; i++ { sort.Slice(rr.G[i], func(j, k int) bool { return rr.G[i][j].to < rr.G[i][k].to }) rr.ld[i] = make([]E, len(rr.G[i])+1) rr.rd[i] = make([]E, len(rr.G[i])+1) for j := range rr.ld[i] { rr.ld[i][j] = e(i) rr.rd[i][j] = e(i) } rr.lp[i] = 0 rr.rp[i] = len(rr.G[i]) - 1 } for i := 0; i < n; i++ { for j := range rr.G[i] { rr.G[i][j].rev = rr.search(rr.G[rr.G[i][j].to], i) } } res := make([]E, n) for i := 0; i < n; i++ { res[i] = rr.dfs(i, -1) } return res } // !root 作为根节点时, 子树 v 的 dp 值 func (rr *ReRootingSubTree) SubTree(root, v int) E { k := rr.search(rr.G[root], v) return rr.composition(rr.dfs(v, rr.G[root][k].rev), rr.G[root][k].data) } func (rr *ReRootingSubTree) dfs(root, eid int) E { for rr.lp[root] != eid && rr.lp[root] < len(rr.G[root]) { e := rr.G[root][rr.lp[root]] rr.ld[root][rr.lp[root]+1] = rr.op(rr.ld[root][rr.lp[root]], rr.composition(rr.dfs(e.to, e.rev), e.data)) rr.lp[root]++ } for rr.rp[root] != eid && rr.rp[root] >= 0 { e := rr.G[root][rr.rp[root]] rr.rd[root][rr.rp[root]] = rr.op(rr.rd[root][rr.rp[root]+1], rr.composition(rr.dfs(e.to, e.rev), e.data)) rr.rp[root]-- } if eid < 0 { return rr.rd[root][0] } return rr.op(rr.ld[root][eid], rr.rd[root][eid+1]) } func (rr *ReRootingSubTree) search(vs []Node, idx int) int { return sort.Search(len(vs), func(i int) bool { return vs[i].to >= idx }) } 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 }