結果
問題 | No.2200 Weird Shortest Path |
ユーザー | kacho65535 |
提出日時 | 2023-02-14 12:16:02 |
言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 213 ms / 2,000 ms |
コード長 | 6,299 bytes |
コンパイル時間 | 2,406 ms |
コンパイル使用メモリ | 218,812 KB |
実行使用メモリ | 10,424 KB |
最終ジャッジ日時 | 2024-07-16 23:32:18 |
合計ジャッジ時間 | 10,608 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 3 ms
5,376 KB |
testcase_04 | AC | 4 ms
5,376 KB |
testcase_05 | AC | 3 ms
5,376 KB |
testcase_06 | AC | 3 ms
5,376 KB |
testcase_07 | AC | 3 ms
5,376 KB |
testcase_08 | AC | 3 ms
5,376 KB |
testcase_09 | AC | 4 ms
5,376 KB |
testcase_10 | AC | 2 ms
5,376 KB |
testcase_11 | AC | 3 ms
5,376 KB |
testcase_12 | AC | 2 ms
5,376 KB |
testcase_13 | AC | 2 ms
5,376 KB |
testcase_14 | AC | 3 ms
5,376 KB |
testcase_15 | AC | 4 ms
5,376 KB |
testcase_16 | AC | 2 ms
5,376 KB |
testcase_17 | AC | 85 ms
5,376 KB |
testcase_18 | AC | 111 ms
7,424 KB |
testcase_19 | AC | 197 ms
8,576 KB |
testcase_20 | AC | 186 ms
9,344 KB |
testcase_21 | AC | 72 ms
6,940 KB |
testcase_22 | AC | 99 ms
6,784 KB |
testcase_23 | AC | 200 ms
9,420 KB |
testcase_24 | AC | 36 ms
5,376 KB |
testcase_25 | AC | 193 ms
8,960 KB |
testcase_26 | AC | 206 ms
9,184 KB |
testcase_27 | AC | 70 ms
6,272 KB |
testcase_28 | AC | 148 ms
8,028 KB |
testcase_29 | AC | 199 ms
9,600 KB |
testcase_30 | AC | 196 ms
9,108 KB |
testcase_31 | AC | 121 ms
7,424 KB |
testcase_32 | AC | 199 ms
10,368 KB |
testcase_33 | AC | 205 ms
10,368 KB |
testcase_34 | AC | 202 ms
10,252 KB |
testcase_35 | AC | 197 ms
10,240 KB |
testcase_36 | AC | 198 ms
10,240 KB |
testcase_37 | AC | 199 ms
10,240 KB |
testcase_38 | AC | 204 ms
10,240 KB |
testcase_39 | AC | 106 ms
7,936 KB |
testcase_40 | AC | 159 ms
10,240 KB |
testcase_41 | AC | 89 ms
7,936 KB |
testcase_42 | AC | 142 ms
10,368 KB |
testcase_43 | AC | 213 ms
10,424 KB |
testcase_44 | AC | 209 ms
10,368 KB |
testcase_45 | AC | 212 ms
10,240 KB |
コンパイルメッセージ
main.cpp:1:25: warning: extra tokens at end of #include directive 1 | #include <bits/stdc++.h>#pragma GCC optimize("Ofast") | ^ main.cpp: In function 'int main()': main.cpp:216:10: warning: ISO C++17 does not allow 'register' storage class specifier [-Wregister] 216 | loop(i, M) | ^ main.cpp:12:38: note: in definition of macro 'loop' 12 | #define loop(i, n) for (register int i = 0; i < n; i++) | ^ main.cpp:226:10: warning: ISO C++17 does not allow 'register' storage class specifier [-Wregister] 226 | loop(i, M) | ^ main.cpp:12:38: note: in definition of macro 'loop' 12 | #define loop(i, n) for (register int i = 0; i < n; i++) | ^
ソースコード
#include <bits/stdc++.h>#pragma GCC optimize("Ofast") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #pragma GCC target("avx") #include <bits/stdc++.h> using namespace std; using ll = long long; using vec = vector<ll>; using vect = vector<double>; using Graph = vector<vector<ll>>; #define endl '\n' #define loop(i, n) for (register int i = 0; i < n; i++) #define Loop(i, m, n) for (int i = m; i < n; i++) #define pool(i, n) for (int i = n; i >= 0; i--) #define Pool(i, m, n) for (int i = n; i >= m; i--) #define modd 1000000007ll // #define modd 998244353ll #define flagcount(bit) __builtin_popcount(bit) #define flag(x) (1ll << x) #define flagadd(bit, x) bit |= flag(x) #define flagpop(bit, x) bit &= ~flag(x) #define flagon(bit, i) bit &flag(i) #define flagoff(bit, i) !(bit & (1ll << i)) #define all(v) v.begin(), v.end() #define low2way(v, x) lower_bound(all(v), x) #define high2way(v, x) upper_bound(all(v), x) #define idx_lower(v, x) (distance(v.begin(), low2way(v, x))) // 配列vでx未満の要素数を返す #define idx_upper(v, x) (distance(v.begin(), high2way(v, x))) // 配列vでx以下の要素数を返す #define idx_lower2(v, x) (v.size() - idx_lower(v, x)) // 配列vでx以上の要素数を返す #define idx_upper2(v, x) (v.size() - idx_upper(v, x)) // 配列vでxより大きい要素の数を返す #define idx_count(v, l, r) max(0, (int)(idx_upper(v, r) - idx_lower(v, l))) // 配列vでl<=x<=rを満たす要素xの数を返す #define putout(a) cout << a << '\n' #define Sum(v) accumulate(all(v), 0ll) ll ctoi(char c) { if (c >= '0' && c <= '9') { return c - '0'; } return -1; } template <typename T> string make_string(T N) { string ret; T now = N; while (now > 0) { T x = now % 10; ret += (char)('0' + x); now /= 10; } reverse(all(ret)); return ret; } template <typename T> T gcd(T a, T b) { if (a % b == 0) { return (b); } else { return (gcd(b, a % b)); } } template <typename T> T lcm(T x, T y) { T z = gcd(x, y); return x * y / z; } template <typename T> bool primejudge(T n) { if (n < 2) return false; else if (n == 2) return true; else if (n % 2 == 0) return false; double sqrtn = sqrt(n); for (T i = 3; i < sqrtn + 1; i++) { if (n % i == 0) { return false; } i++; } return true; } template <typename T> bool chmax(T &a, const T &b) { if (a < b) { a = b; // aをbで更新 return true; } return false; } template <typename T> bool chmin(T &a, const T &b) { if (a > b) { a = b; // aをbで更新 return true; } return false; } // 場合によって使い分ける const ll dx[4] = {1, 0, -1, 0}; const ll dy[4] = {0, 1, 0, -1}; // const ll dx[8] = {1, 1, 0, -1, -1, -1, 0, 1}; // const ll dy[8] = {0, 1, 1, 1, 0, -1, -1, -1}; // cout << fixed << setprecision(10); // vector<vector<ll>> field(h, vector<ll>(w)); template <typename T> void putA(vector<T> &A) { int sz = A.size(); for (int i = 0; i < sz; i++) { cout << A[i]; if (i != sz - 1) cout << " "; else cout << "" << endl; } } ll extgcd(ll a, ll b, ll &x, ll &y) { if (b == 0) { x = 1; y = 0; return a; } ll d = extgcd(b, a % b, y, x); y -= a / b * x; return d; } struct union_find { vector<long long> par; // 親の番号 vector<long long> rank; // 木の深さ(根のランクは0) vector<long long> siz; // 要素xが根なら木の頂点数を格納する // 初期化子リストを用いた初期化 union_find(long long N) : par(N), rank(N), siz(N) { for (long long i = 0; i < N; i++) { par[i] = i; rank[i] = 0; siz[i] = 1; } } // 要素xが所属する木の根を再帰的に発見する long long root(long long x) { if (par[x] == x) return x; return par[x] = root(par[x]); // 経路圧縮 } // 要素xが属する木と要素yが属する木の併合 void unite(long long x, long long y) { long long rx = root(x); long long ry = root(y); if (rx == ry) return; // 同じ木に属してたらそのまま if (rank[rx] < rank[ry]) { par[rx] = ry; // 根がryの木に併合 siz[ry] = siz[rx] + siz[ry]; } else { par[ry] = rx; // 根がrxの木に併合 siz[rx] = siz[rx] + siz[ry]; if (rank[rx] == rank[ry]) rank[rx]++; } } // 要素xが属する木と要素yが属する木が同じならtrueを返す bool same(long long x, long long y) { return root(x) == root(y); } // 要素xが属する木の頂点数を返す long long size(long long x) { return siz[root(x)]; } }; int main() { /* どういう問題か Σ{1<=u<v<=N} min{u,v間の全てのパス} max(u,v間のパスに含まれる辺の重み) を求める。 f(u,v):min{u,v間の全てのパス} max(u,v間のパスに含まれる辺の重み) とする。 辺を小さい順に構築していく。 すると、あるu,vについてu-v間が連結になった瞬間、そのときに結ばれた辺の重みw=f(u,v)となる。 後は、辺を追加するときに、どのu,v間を連結にしたかが分かればよい。これは併合する2つの集合のサイズの積に等しい。 解けた! */ ll N, M; cin >> N >> M; ll ans = 0; vector<tuple<ll, ll, ll>> edges(M); loop(i, M) { ll a, b, w; cin >> a >> b >> w; a--; b--; edges[i] = make_tuple(w, a, b); } sort(all(edges)); union_find tree(N); loop(i, M) { ll w = get<0>(edges[i]), a = get<1>(edges[i]), b = get<2>(edges[i]); if (tree.same(a, b)) continue; ans += tree.size(a) * tree.size(b) * w; tree.unite(a, b); } putout(ans); return 0; }