Submission #53755
ソースコード
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | #include "bits/stdc++.h" #define rep(i, n) for (i64 i = 0, i##_limit = (n); i < i##_limit; ++i) using namespace std; using i64 = int_fast64_t; template < class T, class U> inline bool chmax(T &a, const U &b){ return b>a && (a=b, true );} template < class T, class U> inline bool chmin(T &a, const U &b){ return b<a && (a=b, true );} constexpr int INF = 0x3f3f3f3f; constexpr i64 LINF = 0x3f3f3f3f3f3f3f3fLL; struct Edge { // {{{ int src, to; int64_t cost = 0; inline Edge( int src, int to, const int64_t &cost) noexcept : src(src), to(to), cost(cost) {} inline Edge( int to, const int64_t &cost) noexcept : src(-1), to(to), cost(cost) {} inline Edge() noexcept {} bool operator< ( const Edge &o) const noexcept { return cost < o.cost; } bool operator> ( const Edge &o) const noexcept { return o < * this ; } Edge& operator=( int to) noexcept { this ->to = to; return * this ; } operator int () const noexcept { return to; } }; // }}} using WeightedGraph = vector<vector<Edge>>; using UnWeightedGraph = vector<vector< int >>; class HeavyLightDecomposition { // {{{ public : WeightedGraph G; // 重み付きグラフ const int V; // ノード数 vector< int > parent; // 親 vector< int > treeSize; // 自分も含めた部分木のサイズ vector< int > head; // HL分解後の自分が属するグループ(チェイン)の先頭ノード vector< int > vid; // 根からDFSしたときにそのノードを訪れた順番 vector< int > nodeOfVid; // vidからノードを逆算する用 vector<int64_t> weightSum; // 根からのコストの総和 vector< int > depth; // 根からの深さ(経由するエッジの数) HeavyLightDecomposition() = delete ; // 空の木を構築する。管理できるノードは [0, V) なので注意。 explicit HeavyLightDecomposition( int V) : G(V), V(V), parent(V, -1), treeSize(V), head(V), vid(V), nodeOfVid(V), weightSum(V, 0), depth(V, 0) {} // u-v間に無向辺を張る。重みは省略可 inline void addEdge( int u, int v, int64_t weight = 1) { G[u].emplace_back(u, v, weight); G[v].emplace_back(v, u, weight); } // HL分解、その他もろもろ前計算 void build( int root = 0) { int timestamp = 0; head[root] = root; dfs_treeSize(root); dfs_HLDecomp(root, timestamp); } // u,v の最小共通祖先を求める int lca( int u, int v) const { while (head[u] != head[v]) { if (vid[u] > vid[v]) swap(u, v); v = parent[head[v]]; } return (vid[u] < vid[v]) ? u : v; } // 根に向かって v から k だけ登ったノードを求める int climb( int v, int k) const { while (1) { const int h = head[v]; if (vid[v] - k >= vid[h]) return nodeOfVid[vid[v] - k]; k -= vid[v] - vid[h] + 1; v = parent[h]; } } // u-v間のパスの重みの和を求める int64_t pathWeight( int u, int v) const { return weightSum[u] + weightSum[v] - (2 * weightSum[lca(u, v)]); } // u-v間のパスの「エッジの個数」を求める int pathCountEdge( int u, int v) const { return depth[u] + depth[v] - (2 * depth[lca(u, v)]) + 1; } private : // {{{ // treeSize[v], parent[v], depth[v], weightSum[v] を再帰によって計算 // v の子の中で最もheavyなやつを G[v] の先頭にもってくる int dfs_treeSize( int v) { treeSize[v] = 1; if (!G[v].empty() && G[v].front().to == parent[v]) swap(G[v].front(), G[v].back()); for (auto &e : G[v]) { if (e.to == parent[v]) continue ; parent[e.to] = v; depth[e.to] = depth[v] + 1; weightSum[e.to] = weightSum[v] + e.cost; treeSize[v] += dfs_treeSize(e.to); if (treeSize[e.to] > treeSize[G[v].front()]) swap(e, G[v].front()); } return treeSize[v]; } // G[v] の先頭に v の子中で最もheavyなノードがある前提でHL分解し、 // vid[v], nodeOfVid[v], head[v] を求める void dfs_HLDecomp( int v, int ×tamp) { vid[v] = timestamp; nodeOfVid[timestamp] = v; ++timestamp; for ( const int to : G[v]) { if (to == parent[v]) continue ; head[to] = (to == G[v].front() ? head[v] : to); dfs_HLDecomp(to, timestamp); } } // }}} }; // }}} signed main() { ios::sync_with_stdio( false ); cin.tie(nullptr); int N, Q; cin >> N >> Q; HeavyLightDecomposition G(N+1); rep(i, N - 1) { int u, v, w; cin >> u >> v >> w; G.addEdge(u, v, w); } // 根のノードを1としてHL分解 G.build(1); // a-b, a-c, b-c の3つのパスの中で重みが最大のものを探し、 // { パスの始点, パスの終点 } のペアを返す。 const auto maxWeightPath = [&G]( int a, int b, int c) -> pair< int , int > { const auto weightAB = G.pathWeight(a, b); const auto weightAC = G.pathWeight(a, c); const auto weightBC = G.pathWeight(b, c); const auto maxv = max({ weightAB, weightAC, weightBC }); if (maxv == weightAB) return { a, b }; if (maxv == weightAC) return { a, c }; return { b, c }; }; // s からlcaに向かって登る距離を [low, high) で2分探索 // (パス[s-lca]上で、weight(s, p) < weight(t, p) を満たし、s からできるだけ離れたノードを探索) // 探索途中のノードも解の候補に含めるので逐次 res を更新する const auto binSearch = [&G]( int s, int lca, int t) -> i64 { i64 res = LINF; int low = 0; int high = G.pathCountEdge(s, lca) + 1; while (high - low > 1) { const int mid = (low + high) / 2; const int p = G.climb(s, mid); const auto weightSP = G.pathWeight(s, p); const auto weightTP = G.pathWeight(t, p); chmin(res, max(weightSP, weightTP)); if (weightSP < weightTP) { low = mid; } else { high = mid; } } const int p = G.climb(s, low); chmin(res, max(G.pathWeight(s, p), G.pathWeight(t, p))); return res; }; const auto solve = [&]( int a, int b, int c) -> i64 { int s, t; tie(s, t) = maxWeightPath(a, b, c); const int lca = G.lca(s, t); return min(binSearch(s, lca, t), binSearch(t, lca, s)); }; rep(i, Q) { int a, b, c; cin >> a >> b >> c; cout << solve(a, b, c) << "\n" ; } return 0; } |
ステータス
項目 | データ |
---|---|
問題 | 1024 - 待ち合わせ |
ユーザー名 | Arumakan_ei1727 |
投稿日時 | 2019-08-28 22:02:00 |
言語 | C++14 |
状態 | Accepted |
得点 | 14 |
ソースコード長 | 7057 Byte |
最大実行時間 | 188 ms |
最大メモリ使用量 | 86988 KB |
セット
セット | 得点 | Cases | |
---|---|---|---|
1 | ALL | 14 / 14 | * |
テストケース
ファイル名 | 状態 | 実行時間 | メモリ使用量 | # |
---|---|---|---|---|
in1.txt | AC | 42 ms | 604 KB |
1
|
in2.txt | AC | 22 ms | 556 KB |
1
|
in3.txt | AC | 19 ms | 676 KB |
1
|
in4.txt | AC | 24 ms | 14728 KB |
1
|
in5.txt | AC | 19 ms | 47548 KB |
1
|
in6.txt | AC | 20 ms | 73820 KB |
1
|
in7.txt | AC | 18 ms | 74024 KB |
1
|
in8.txt | AC | 19 ms | 73976 KB |
1
|
in9.txt | AC | 23 ms | 73924 KB |
1
|
in10.txt | AC | 32 ms | 560 KB |
1
|
in11.txt | AC | 21 ms | 640 KB |
1
|
in12.txt | AC | 29 ms | 592 KB |
1
|
in13.txt | AC | 24 ms | 668 KB |
1
|
in14.txt | AC | 36 ms | 612 KB |
1
|
in15.txt | AC | 23 ms | 560 KB |
1
|
in16.txt | AC | 25 ms | 640 KB |
1
|
in17.txt | AC | 15 ms | 588 KB |
1
|
in18.txt | AC | 55 ms | 664 KB |
1
|
in19.txt | AC | 19 ms | 484 KB |
1
|
in20.txt | AC | 19 ms | 512 KB |
1
|
in21.txt | AC | 22 ms | 588 KB |
1
|
in22.txt | AC | 30 ms | 528 KB |
1
|
in23.txt | AC | 21 ms | 596 KB |
1
|
in24.txt | AC | 22 ms | 668 KB |
1
|
in25.txt | AC | 20 ms | 740 KB |
1
|
in26.txt | AC | 41 ms | 808 KB |
1
|
in27.txt | AC | 22 ms | 868 KB |
1
|
in28.txt | AC | 24 ms | 800 KB |
1
|
in29.txt | AC | 24 ms | 868 KB |
1
|
in30.txt | AC | 22 ms | 752 KB |
1
|
in31.txt | AC | 19 ms | 692 KB |
1
|
in32.txt | AC | 33 ms | 884 KB |
1
|
in33.txt | AC | 21 ms | 948 KB |
1
|
in34.txt | AC | 19 ms | 884 KB |
1
|
in35.txt | AC | 18 ms | 952 KB |
1
|
in36.txt | AC | 139 ms | 22780 KB |
1
|
in37.txt | AC | 145 ms | 17940 KB |
1
|
in38.txt | AC | 144 ms | 19800 KB |
1
|
in39.txt | AC | 175 ms | 25160 KB |
1
|
in40.txt | AC | 147 ms | 26968 KB |
1
|
in41.txt | AC | 144 ms | 30480 KB |
1
|
in42.txt | AC | 98 ms | 33544 KB |
1
|
in43.txt | AC | 87 ms | 35548 KB |
1
|
in44.txt | AC | 92 ms | 38448 KB |
1
|
in45.txt | AC | 127 ms | 43692 KB |
1
|
in46.txt | AC | 142 ms | 46780 KB |
1
|
in47.txt | AC | 188 ms | 49720 KB |
1
|
in48.txt | AC | 149 ms | 54296 KB |
1
|
in49.txt | AC | 135 ms | 57376 KB |
1
|
in50.txt | AC | 130 ms | 60812 KB |
1
|
in51.txt | AC | 141 ms | 65236 KB |
1
|
in52.txt | AC | 147 ms | 71728 KB |
1
|
in53.txt | AC | 124 ms | 76224 KB |
1
|
in54.txt | AC | 136 ms | 78908 KB |
1
|
in55.txt | AC | 129 ms | 83320 KB |
1
|
in56.txt | AC | 124 ms | 86988 KB |
1
|