C++の練習を兼ねて, AtCoder Beginner Contest 239 の 問題E (Subtree K-th Max) を解いてみた.
■感想.
1. 問題Eは, 方針を絞り込めたので, AC版に到達できたと思う.
2. 実装に苦労したものの, 幅優先探索の復習が出来たので, 非常に良かったと思う.
3. 引き続き, 時間を見つけて, 過去問の学習を進めていきたいと思う.
本家のサイト AtCoder Beginner Contest 239 解説 の 各リンク を ご覧下さい.
■C++版プログラム(問題E/AC版).
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 |
// C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using vi = vector<int>; using vvi = vector<vi>; using P = pair<int, int>; using vpq = vector<priority_queue<int>>; #define repex(i, a, b, c) for(int i = a; i < b; i += c) #define repx(i, a, b) repex(i, a, b, 1) #define rep(i, n) repx(i, 0, n) #define repr(i, a, b) for(int i = a; i >= b; i--) #define pb push_back #define a first #define b second #define all(x) x.begin(), x.end() int x[101010]; int main(){ // 1. 入力情報. int N, Q; scanf("%d %d", &N, &Q); rep(i, N) scanf("%d", &x[i]); vvi G(N); rep(i, N - 1){ int a, b; scanf("%d %d", &a, &b); --a; --b; G[a].pb(b); G[b].pb(a); } // 2. bfs. // https://ja.wikipedia.org/wiki/幅優先探索 auto bfs = [&](vvi &G, int s, int* d){ // 空のキュー. queue<int> q; // 探索地点 s をキュー q に追加. q.push(s); while(!q.empty()){ // キューから取り出す. int u = q.front(); q.pop(); // 隣接頂点をチェック. for(auto &e : G[u]) if(!d[e] && e != s) d[e] = d[u] + 1, q.push(e); } }; // 3. 根から各頂点までの最短距離. int d[N]; rep(i, N) d[i] = 0; bfs(G, 0, d); // 4. 頂点 1 から 遠い順 に並び替え. priority_queue<P> pq; rep(i, N) pq.push({d[i], i}); // {距離, 頂点番号}. // 5. 頂点に書かれた整数の保存(大きい方から, 20番目まで). // 5-1. 根以外. vpq t(N); vvi q(N); int n = 0; while(!pq.empty()){ // 頂点 v を一つ取り出す. P p = pq.top(); pq.pop(); // 頂点 v の 頂点番号は? int v = p.b; // 整数を保存. t[v].push(x[v]); // 頂点 v を 根とする部分木 で 集計. for(auto &u : G[v]){ // 頂点 v の 子供 に 相当する頂点 u を 選択. if(d[u] > d[v]){ n = 0; while(n < 20 && !t[u].empty()){ int o = t[u].top(); t[u].pop(); t[v].push(o); q[u].pb(o); n++; } } } } // 5-2. 根. // -> 根については, データの移し替えが未完了なので, ここで対応. // 前項と同様に, 20件以下に, 絞り込む. n = 0; while(n < 20 && !t[0].empty()){ int o = t[0].top(); t[0].pop(); q[0].pb(o); n++; } // 6. sort. rep(i, N){ sort(all(q[i])); reverse(all(q[i])); } // 7. クエリ回答. rep(i, Q){ int v, k; scanf("%d %d", &v, &k); --v; --k; printf("%d\n", q[v][k]); } return 0; } |
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 |
[入力例] 5 2 1 2 3 4 5 1 4 2 1 2 5 3 2 1 2 2 1 [出力例] 4 5 ※AtCoderテストケースより [入力例] 6 2 10 10 10 9 8 8 1 4 2 1 2 5 3 2 6 4 1 4 2 2 [出力例] 9 10 ※AtCoderテストケースより [入力例] 4 4 1 10 100 1000 1 2 2 3 3 4 1 4 2 3 3 2 4 1 [出力例] 1 10 100 1000 ※AtCoderテストケースより [入力例] 10 7 5 5 7 7 8 10 2 3 11 12 1 2 3 1 4 1 3 5 6 3 4 9 10 4 6 7 8 6 2 1 6 2 3 2 1 5 4 1 3 5 1 7 [出力例] 5 3 8 7 12 2 5 [入力例] 20 20 111 22 33 123 222 1 0 7 77 11 88 55 77 55 7 0 1 33 55 88 1 2 1 4 1 16 6 2 6 12 7 6 5 4 3 4 5 11 5 8 10 3 9 3 17 3 10 13 10 14 10 15 18 15 19 15 20 15 1 1 1 2 1 5 1 7 1 20 2 1 2 2 3 1 3 5 3 7 4 1 4 10 5 2 6 2 9 1 10 1 10 2 15 1 15 2 19 1 [出力例] 222 123 88 77 0 55 22 88 55 33 222 33 88 1 77 88 77 88 55 55 |
■参照サイト
デンソークリエイトプログラミングコンテスト2022(AtCoder Beginner Contest 239)