結果
問題 | No.1254 補強への架け橋 |
ユーザー | shirokami |
提出日時 | 2023-08-19 10:28:58 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 127 ms / 2,000 ms |
コード長 | 9,722 bytes |
コンパイル時間 | 5,991 ms |
コンパイル使用メモリ | 344,856 KB |
実行使用メモリ | 38,692 KB |
最終ジャッジ日時 | 2024-11-29 02:03:08 |
合計ジャッジ時間 | 16,987 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,820 KB |
testcase_01 | AC | 1 ms
6,820 KB |
testcase_02 | AC | 1 ms
6,816 KB |
testcase_03 | AC | 1 ms
6,820 KB |
testcase_04 | AC | 2 ms
6,816 KB |
testcase_05 | AC | 1 ms
6,816 KB |
testcase_06 | AC | 1 ms
6,820 KB |
testcase_07 | AC | 2 ms
6,820 KB |
testcase_08 | AC | 2 ms
6,820 KB |
testcase_09 | AC | 1 ms
6,820 KB |
testcase_10 | AC | 1 ms
6,816 KB |
testcase_11 | AC | 2 ms
6,820 KB |
testcase_12 | AC | 2 ms
6,820 KB |
testcase_13 | AC | 1 ms
6,816 KB |
testcase_14 | AC | 2 ms
6,816 KB |
testcase_15 | AC | 2 ms
6,816 KB |
testcase_16 | AC | 1 ms
6,816 KB |
testcase_17 | AC | 2 ms
6,820 KB |
testcase_18 | AC | 2 ms
6,816 KB |
testcase_19 | AC | 1 ms
6,820 KB |
testcase_20 | AC | 1 ms
6,820 KB |
testcase_21 | AC | 2 ms
6,820 KB |
testcase_22 | AC | 2 ms
6,816 KB |
testcase_23 | AC | 1 ms
6,820 KB |
testcase_24 | AC | 2 ms
6,820 KB |
testcase_25 | AC | 2 ms
6,820 KB |
testcase_26 | AC | 2 ms
6,816 KB |
testcase_27 | AC | 2 ms
6,816 KB |
testcase_28 | AC | 2 ms
6,816 KB |
testcase_29 | AC | 2 ms
6,816 KB |
testcase_30 | AC | 2 ms
6,820 KB |
testcase_31 | AC | 2 ms
6,816 KB |
testcase_32 | AC | 2 ms
6,816 KB |
testcase_33 | AC | 2 ms
6,816 KB |
testcase_34 | AC | 2 ms
6,816 KB |
testcase_35 | AC | 2 ms
6,816 KB |
testcase_36 | AC | 1 ms
6,816 KB |
testcase_37 | AC | 2 ms
6,816 KB |
testcase_38 | AC | 2 ms
6,816 KB |
testcase_39 | AC | 2 ms
6,816 KB |
testcase_40 | AC | 2 ms
6,816 KB |
testcase_41 | AC | 2 ms
6,820 KB |
testcase_42 | AC | 2 ms
6,816 KB |
testcase_43 | AC | 3 ms
6,820 KB |
testcase_44 | AC | 2 ms
6,816 KB |
testcase_45 | AC | 2 ms
6,816 KB |
testcase_46 | AC | 2 ms
6,816 KB |
testcase_47 | AC | 2 ms
6,816 KB |
testcase_48 | AC | 2 ms
6,820 KB |
testcase_49 | AC | 2 ms
6,816 KB |
testcase_50 | AC | 2 ms
6,820 KB |
testcase_51 | AC | 2 ms
6,816 KB |
testcase_52 | AC | 3 ms
6,820 KB |
testcase_53 | AC | 3 ms
6,816 KB |
testcase_54 | AC | 3 ms
6,816 KB |
testcase_55 | AC | 3 ms
6,816 KB |
testcase_56 | AC | 2 ms
6,820 KB |
testcase_57 | AC | 3 ms
6,816 KB |
testcase_58 | AC | 3 ms
6,820 KB |
testcase_59 | AC | 2 ms
6,820 KB |
testcase_60 | AC | 2 ms
6,820 KB |
testcase_61 | AC | 3 ms
6,816 KB |
testcase_62 | AC | 2 ms
6,816 KB |
testcase_63 | AC | 9 ms
6,820 KB |
testcase_64 | AC | 4 ms
6,816 KB |
testcase_65 | AC | 7 ms
6,816 KB |
testcase_66 | AC | 6 ms
6,820 KB |
testcase_67 | AC | 4 ms
6,816 KB |
testcase_68 | AC | 5 ms
6,820 KB |
testcase_69 | AC | 7 ms
6,820 KB |
testcase_70 | AC | 3 ms
6,816 KB |
testcase_71 | AC | 4 ms
6,820 KB |
testcase_72 | AC | 7 ms
6,816 KB |
testcase_73 | AC | 4 ms
6,820 KB |
testcase_74 | AC | 7 ms
6,816 KB |
testcase_75 | AC | 6 ms
6,816 KB |
testcase_76 | AC | 2 ms
6,816 KB |
testcase_77 | AC | 5 ms
6,816 KB |
testcase_78 | AC | 9 ms
6,816 KB |
testcase_79 | AC | 9 ms
6,816 KB |
testcase_80 | AC | 7 ms
6,820 KB |
testcase_81 | AC | 9 ms
6,820 KB |
testcase_82 | AC | 8 ms
6,820 KB |
testcase_83 | AC | 127 ms
31,928 KB |
testcase_84 | AC | 79 ms
26,456 KB |
testcase_85 | AC | 47 ms
18,908 KB |
testcase_86 | AC | 72 ms
26,916 KB |
testcase_87 | AC | 79 ms
26,584 KB |
testcase_88 | AC | 13 ms
7,592 KB |
testcase_89 | AC | 113 ms
29,088 KB |
testcase_90 | AC | 56 ms
18,728 KB |
testcase_91 | AC | 45 ms
16,140 KB |
testcase_92 | AC | 23 ms
11,100 KB |
testcase_93 | AC | 71 ms
24,600 KB |
testcase_94 | AC | 60 ms
25,892 KB |
testcase_95 | AC | 66 ms
24,220 KB |
testcase_96 | AC | 89 ms
31,768 KB |
testcase_97 | AC | 34 ms
13,300 KB |
testcase_98 | AC | 75 ms
26,332 KB |
testcase_99 | AC | 47 ms
20,396 KB |
testcase_100 | AC | 91 ms
33,208 KB |
testcase_101 | AC | 19 ms
9,640 KB |
testcase_102 | AC | 10 ms
6,816 KB |
testcase_103 | AC | 20 ms
10,456 KB |
testcase_104 | AC | 30 ms
13,676 KB |
testcase_105 | AC | 65 ms
23,360 KB |
testcase_106 | AC | 40 ms
16,584 KB |
testcase_107 | AC | 91 ms
34,376 KB |
testcase_108 | AC | 83 ms
28,768 KB |
testcase_109 | AC | 62 ms
24,592 KB |
testcase_110 | AC | 62 ms
22,676 KB |
testcase_111 | AC | 63 ms
22,568 KB |
testcase_112 | AC | 28 ms
12,036 KB |
testcase_113 | AC | 57 ms
23,068 KB |
testcase_114 | AC | 37 ms
16,676 KB |
testcase_115 | AC | 14 ms
7,468 KB |
testcase_116 | AC | 43 ms
18,644 KB |
testcase_117 | AC | 29 ms
13,540 KB |
testcase_118 | AC | 77 ms
28,924 KB |
testcase_119 | AC | 45 ms
20,128 KB |
testcase_120 | AC | 80 ms
31,092 KB |
testcase_121 | AC | 25 ms
10,652 KB |
testcase_122 | AC | 42 ms
18,412 KB |
testcase_123 | AC | 2 ms
6,816 KB |
testcase_124 | AC | 100 ms
38,080 KB |
testcase_125 | AC | 106 ms
38,692 KB |
ソースコード
#include <bits/extc++.h> using namespace std; // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") // using namespace __gnu_pbds; // #include <boost/multiprecision/cpp_int.hpp> // using Bint = boost::multiprecision::cpp_int; // #include <atcoder/all> // using namespace atcoder; // https://atcoder.github.io/ac-library/production/document_ja/ using uint = unsigned int; using ll = long long; using ull = unsigned long long; using ld = long double; constexpr ll mod = 1e9+7; constexpr ll INF = 9'223'372'036'854'775'807/10; #define rep(i,n) for (uint i = 0; i < uint(n); ++i) #define All(a) (a).begin(),(a).end() #define PI acos(-1) vector<ll> dx = {1, 0, -1, 0, 1, 1, -1, -1}; vector<ll> dy = {0, 1, 0, -1, 1, -1, 1, -1}; template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; } template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; } struct Edge { uint from, to; long long cost; int idx; Edge() {} Edge(uint from_, uint to_, long long cost_ = 1, int idx_ = -1) : from(from_), to(to_), cost(cost_), idx(idx_) {} bool operator<(const Edge &e) const { return cost < e.cost; } bool operator>(const Edge &e) const { return cost > e.cost; } friend ostream& operator<<(ostream& os, const Edge& e) { os << e.from << " " << e.to << " (" << e.cost << ")"; return os; } operator int() const { return to; } }; struct Graph { vector<vector<Edge>> G; vector<Edge> edges; Graph() {} Graph(uint n) : G(n) {} void add_edge(uint from, uint to, ll cost = 1, int idx = -1) { G[from].emplace_back(from, to, cost, idx); edges.emplace_back(from, to, cost, idx); } size_t size() const { return G.size(); } vector<Edge>& operator[](int k) { return G[k]; } friend ostream& operator<<(ostream& os, Graph& g) { for (uint i = 0; i < g.size(); i++) { for (Edge e : g[i]) { cout << e << '\n'; } } return os; } }; struct IoSetup { IoSetup() { cin.tie(nullptr); ios_base::sync_with_stdio(false); cout << setprecision(15) << fixed; } } iosetup; void print(const vector<string> &v) { for (string s : v) { cout << s << '\n'; } } template<typename T> void print(const vector<pair<T, T>> &v, uint w = 0) { for (uint i = 0; i < (uint)v.size(); i++) { cout << right << setw(w) << v[i].first << ' ' << v[i].second << '\n'; } } template<typename T> void print(const vector<T> &v, uint w = 0) { for (uint i = 0; i < (uint)v.size(); i++) { cout << right << setw(w) << v[i] << " \n"[i == (int)v.size() - 1]; } } template<typename T> void print(const vector<vector<T>> &v, uint w = 0) { for (uint i = 0; i < (uint)v.size(); i++) { print(v[i], w); } } template<typename T> void print(const T& arg) { cout << arg << '\n'; } template<typename T, typename... Args> void print(const T& arg, const Args&... args) { cout << arg << ' '; print(args...); } template<typename T> istream& operator>>(istream& is, vector<T>& vec) { for (auto& x : vec) is >> x; return is; } /* なもりグラフ (NamoriGraph) 使い方: NamoriGraph ng(n); ng.add_edge(from, to, cost, idx); (0-indexed). 1回の add_edge で2本の辺 (無向グラフ) が追加される ng.build(); ng.forest[i]: 分解された木の i 番目 (0-indexed). from, to は振り直された頂点番号 (0-indexed), cost, idx は元のグラフの辺のコストとインデックス ng.loop_edges[i]: サイクルに属する i 番目 (0-indexed) の辺. from, to, cost, idx は元のグラフをコピー. ng[k]: 頂点 k について, tree_id, 振り直された木の頂点番号 id を返す ng.inv(tree_id, id): tree_id の頂点 id について、元のグラフの頂点番号を返す. 特に id = 0 はサイクル上の頂点 計算量: O(n) 参考: https://ei1333.github.io/library/graph/others/namori-graph.hpp */ struct NamoriGraph { // g: 元のグラフ // forest: サイクルの任意の頂点を根とした木の集合 // loop_edges: サイクルの辺の集合 // iv: 木の番号, 頂点番号 -> 元のグラフの頂点番号 // iv[i][j]: i番目の木のj番目の頂点の元のグラフの頂点番号 // mark_id: 元のグラフの頂点番号 -> 木の番号 // id: 元のグラフの頂点番号 -> 木の頂点番号 Graph g; vector<Graph> forest; vector<Edge> loop_edges; vector<vector<int>> iv; vector<int> mark_id, id; NamoriGraph() {} NamoriGraph(uint n) : g(n) {} NamoriGraph(const Graph &g_) : g(g_) {} void add_edge(uint from, uint to, long long cost = 1, int idx = -1) { if (idx == -1) idx = (int)g.edges.size()/2; // 無向グラフなので idx = 辺の数/2 g.add_edge(from, to, cost, idx); g.add_edge(to, from, cost, idx); } struct Info { // tree_id: 木の番号 // id: 木の頂点番号 int tree_id, id; }; // 頂点 k について, tree_id, 振り直された木の頂点番号 id を返す Info operator[](const int &k) const { return (Info){mark_id[k], id[k]}; } // tree_id の頂点 id について、元のグラフの頂点番号を返す // 特に id = 0 はサイクル上の頂点 int inv(int tree_id, int id_) { return iv[tree_id][id_]; } void build() { int n = g.size(); // deg: 次数 // used: 使ったかどうか vector<int> deg(n), used(n); queue<int> que; // 次数が 1 の頂点 (先端) をキューに入れる for (int i = 0; i < n; i++) { deg[i] = g[i].size(); if (deg[i] == 1) { que.emplace(i); used[i] = true; } } while (!que.empty()) { int idx = que.front(); que.pop(); for (Edge &e : g[idx]) { if (used[e.to]) { continue; } // 次数が 1 の頂点の隣接頂点の次数を 1 減らす deg[e.to]--; // 次数が 1 (サイクルに未到達)ならキューに入れる if (deg[e.to] == 1) { que.emplace(e.to); used[e.to] = true; } } } vector<int> edge_used(g.edges.size()/2 + 1); vector<int> loop; // loop を探す for (int v = 0; v < n; v++) { // loop の点を 1 個見つける if (!used[v]) { // それを起点に他のループを探す for (bool update = true; update; ) { update = false; loop.emplace_back(v); // 隣接頂点が loop じゃない or すでに使っている辺ならスキップ for (Edge &e : g[v]) { if (used[e.to] || edge_used[e.idx]) { // edge_used の初期化!!!!!!!!!!! continue; } edge_used[e.idx] = true; // e.idx の辺を使用 loop_edges.emplace_back(v, e.to, e.cost, e.idx); // 使った辺を追加 v = e.to; // 次のループ点 update = true; break; } } break; } } // 起点となる頂点が重複しているので削除 loop.pop_back(); mark_id.resize(n); id.resize(n); for (int i = 0; i < (int)loop.size(); i++) { int pre = loop[(i + (int)loop.size() - 1) % loop.size()]; // 前のループ点 int cur = loop[i]; // 現在のループ点 int nxt = loop[(i + 1) % loop.size()]; // 次のループ点 int sz = 0; // 木の頂点番号 // mark_id: 元のグラフの頂点番号 -> 木の番号 mark_id[cur] = i; // iv[i][j]: i番目の木のj番目の頂点の元のグラフの頂点番号 iv.emplace_back(); iv.back().emplace_back(cur); // 木の頂点番号を振り直す id[cur] = sz++; for (Edge &e : g[cur]) { if (e.to != pre && e.to != nxt) { // サイクル上の点でなければ mark_dfs(e.to, cur, i, sz); // 木の頂点番号を振り直す } } Graph tree(sz); for (Edge &e : g[cur]) { if (e.to != pre && e.to != nxt) { // サイクル上の点でなければ tree[id[cur]].emplace_back(id[cur], id[e.to], e.cost, e.idx); // 木の辺を追加 tree[id[e.to]].emplace_back(id[e.to], id[cur], e.cost, e.idx); // 木の辺を追加 build_dfs(e.to, cur, tree); // 再帰 } } forest.emplace_back(tree); // 木を追加 } } // mark_dfs: 木の頂点番号を振り直す // idx: 現在の頂点 // par: 親 // tree_id: 木の番号 // sz: 木の頂点番号 void mark_dfs(int idx, int par, int tree_id, int &sz) { mark_id[idx] = tree_id; // idx の頂点は tree_id 番目の木に属する iv[tree_id].emplace_back(idx); // tree_id 番目の木の sz 番目の頂点は idx id[idx] = sz++; // idx の頂点は sz 番目の頂点 for (Edge &e : g[idx]) { // idx の隣接頂点について if (e.to != par) { // 親でなければ mark_dfs(e.to, idx, tree_id, sz); // 再帰 } } } void build_dfs(int idx, int par, Graph &tree) { for (Edge &e : g[idx]) { // idx の隣接頂点について if (e.to != par) { // 親でなければ tree[id[idx]].emplace_back(id[idx], id[e.to], e.cost, e.idx); // 木の辺を追加 tree[id[e.to]].emplace_back(id[e.to], id[idx], e.cost, e.idx); // 木の辺を追加 build_dfs(e.to, idx, tree); // 再帰 } } } }; void solve() { ll n; cin >> n; NamoriGraph ng(n); rep(i,n) { ll a, b; cin >> a >> b; a--; b--; ng.add_edge(a, b); } ng.build(); cout << ng.loop_edges.size() << '\n'; for (auto e : ng.loop_edges) { cout << e.idx+1 << ' '; } cout << '\n'; } int main() { uint t = 1; // cin >> t; while (t--) { solve(); } }