結果
問題 | No.399 動的な領主 |
ユーザー | Harui |
提出日時 | 2024-07-30 23:57:26 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 242 ms / 2,000 ms |
コード長 | 5,355 bytes |
コンパイル時間 | 1,680 ms |
コンパイル使用メモリ | 112,804 KB |
実行使用メモリ | 17,280 KB |
最終ジャッジ日時 | 2024-07-30 23:57:32 |
合計ジャッジ時間 | 5,275 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,940 KB |
testcase_02 | AC | 2 ms
6,944 KB |
testcase_03 | AC | 2 ms
6,940 KB |
testcase_04 | AC | 3 ms
6,940 KB |
testcase_05 | AC | 18 ms
6,944 KB |
testcase_06 | AC | 214 ms
12,416 KB |
testcase_07 | AC | 242 ms
12,416 KB |
testcase_08 | AC | 214 ms
12,672 KB |
testcase_09 | AC | 213 ms
12,672 KB |
testcase_10 | AC | 3 ms
6,940 KB |
testcase_11 | AC | 17 ms
6,944 KB |
testcase_12 | AC | 177 ms
13,056 KB |
testcase_13 | AC | 179 ms
13,056 KB |
testcase_14 | AC | 154 ms
17,272 KB |
testcase_15 | AC | 134 ms
17,280 KB |
testcase_16 | AC | 149 ms
15,872 KB |
testcase_17 | AC | 222 ms
12,672 KB |
testcase_18 | AC | 220 ms
12,672 KB |
ソースコード
#line 1 "playground_A.cpp" #include <iostream> #line 1 "/home/samejima/CompetitiveProgramming/library/graph/tree/heavy_light_decomposition.hpp" #include <vector> #include <algorithm> #include <cassert> #include <utility> #line 1 "/home/samejima/CompetitiveProgramming/library/graph/graph_template.hpp" #line 5 "/home/samejima/CompetitiveProgramming/library/graph/graph_template.hpp" template <typename T> struct Edge { int from; int to; T cost; Edge(int _from, int _to, T _cost) : from(_from), to(_to), cost(_cost) {} // unweighted Edge(int _from, int _to) : from(_from), to(_to), cost(T(1)) {} bool operator==(const Edge& rhs) { return from == rhs.from && to == rhs.to && cost == rhs.cost; } }; template <typename T> struct Graph : std::vector<std::vector<Edge<T>>> { using std::vector<std::vector<Edge<T>>>::vector; // inherit constructors void add_edge(int i, Edge<T> e) { (*this)[i].push_back(e); } // weighted void add_edge(int _from, int _to, T _cost) { (*this)[_from].push_back(Edge(_from, _to, _cost)); } // unweighted void add_edge(int _from, int _to) { (*this)[_from].push_back(Edge(_from, _to, T(1))); } }; #line 10 "/home/samejima/CompetitiveProgramming/library/graph/tree/heavy_light_decomposition.hpp" // cf : https://ngtkana.hatenablog.com/entry/2024/06/24/200138 struct Interval { // i : interval のもっとも根に近い頂点のid // j : interval のもっとも葉に近い頂点のid // last : LCAを含む interval であるかどうか // reverse : from → to と i → jが逆向きかどうか int i, j; bool last; bool reverse; Interval(int _i, int _j, bool _last, bool _reverse) : i(_i), j(_j), last(_last), reverse(_reverse) { } }; using Path = std::vector<Interval>; struct HLD { //vector<vector<int>>children; std::vector<int>parent; std::vector<int> id; std::vector<int> id2; std::vector<int> head; std::vector<int>depth; Graph<int>graph; HLD (int N) : parent(std::vector<int>(N, -1)), id(std::vector<int>(N)), id2(std::vector<int>(N)), head(std::vector<int>(N)), depth(std::vector<int>(N)), graph(N) {} void build(int root=0) { dfs_sz(root); int k = 0; dfs_hld(root, k); } int dfs_sz(int v) { int ret = 1, mx_sz = 0; for (Edge<int>& nxt : graph[v]) { if (nxt.to == parent[v]) continue; parent[nxt.to] = v; depth[nxt.to] = depth[v] + 1; int sz = dfs_sz(nxt.to); ret += sz; if (mx_sz < sz) { mx_sz = sz; std::swap(graph[v][0], nxt); } } return ret; } void dfs_hld(int v, int& k) { id[v] = k; k++; for (Edge e : graph[v]) { if (e.to == parent[v]) continue; head[e.to] = (e == graph[v][0] ? head[v] : e.to); dfs_hld(e.to, k); } id2[v] = k; } int lca(int u, int v) { while (true) { if (id[u] > id[v]) std::swap(u, v); if (head[u] == head[v]) return u; v = parent[head[v]]; } } Path get_path(int u, int v) { Path upath, vpath; while (head[u] != head[v]) { // ちなみにu,vのdepthの大小関係は変わり続けることもある。 // 10 → 12など。 // v's head is deeper if (depth[head[v]] >= depth[head[u]]) { assert(depth[head[v]] >= depth[head[u]]); /* / : heavy edge .... : light edge head[u] / /... u ... / head[v] / \ / \ / v */ // u→v なのでreverse=false vpath.emplace_back(id[head[v]], id[v], false, false); v = parent[head[v]]; } // u's head is deeper else if (depth[head[v]] < depth[head[u]]) { /* / : heavy edge .... : light edge head[v] / /... v ... / head[u] / \ / \ / u */ // upath.emplace_back(id[head[u]], id[u], false, true); u = parent[head[u]]; } } // v is deeper /* u / / ←↓ / v */ if (depth[v] > depth[u]) { upath.emplace_back(id[u], id[v], true, false); } // u is deeper /* v / / →↑ / u */ else { upath.emplace_back(id[v], id[u], true, true); } Path retpath = upath; reverse(vpath.begin(), vpath.end()); for (Interval path : vpath) retpath.push_back(path); return retpath; } std::pair<int,int> subtree_query(int r) { assert(r < int(id.size())); return std::make_pair(id[r], id2[r]); } }; #line 3 "playground_A.cpp" using namespace std; int main() { int N; cin >> N; HLD hld(N); for (int i=0; i<N-1; i++) { int u, v; cin >> u >> v; u--; v--; hld.graph.add_edge(u,v); hld.graph.add_edge(v,u); } hld.build(); vector<long> cusum(N+1); int Q; cin >> Q; for (int q=0; q<Q; q++) { int A, B; cin >> A >> B; A--; B--; for (Interval intv : hld.get_path(A,B)) { cusum[intv.i] += 1; cusum[intv.j+1] -= 1; } } long ans = 0; for (int i=0; i<N; i++) { cusum[i+1] += cusum[i]; ans += cusum[i] * (cusum[i] + 1) / 2; } cout << ans << endl; }