結果
問題 | No.1390 Get together |
ユーザー |
![]() |
提出日時 | 2021-02-12 21:37:23 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 170 ms / 2,000 ms |
コード長 | 15,886 bytes |
コンパイル時間 | 938 ms |
コンパイル使用メモリ | 99,524 KB |
実行使用メモリ | 13,696 KB |
最終ジャッジ日時 | 2024-07-19 20:37:21 |
合計ジャッジ時間 | 5,024 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 29 |
ソースコード
#include <vector>#include <map>#include <set>#include <cmath>#include <iostream>#include <algorithm>#include <queue>#include <iomanip>#include <list>#include <string>typedef char SINT8;typedef short SINT16;typedef int SINT32;typedef long long SINT64;typedef double DOUBLE;#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))#define CHMAX(a,b) a = MAX(a,b)#define CHMIN(a,b) a = MIN(a,b)#define ABS(a) ((a)>(0)?(a):-(a))#define rep(i,a,b) for(SINT64 (i)=SINT64(a);(i)<SINT64(b);(i)++)#define rrep(i,a,b) for(SINT64 (i)=SINT64(a);(i)>=SINT64(b);(i)--)#define put(a) cout << (a) << endl#define puts(a) cout << (a) << " "#define putr(a) rep(testIncrement,0,a.size()) {puts(a[testIncrement]);} cout << endl#define putrr(a) rep(Incr1,0,a.size()) {rep(Incr2,0,a[Incr1].size()) {puts(a[Incr1][Incr2]);} cout<<endl;} cout<<endl;#define INF 1000000001#define MOD 1000000007#define INF64 1000000000000000001#define PI (acos(-1))#define F first#define S second#define Pll pair<SINT64,SINT64>#define Plll pair<SINT64,pair<SINT64,SINT64>>using namespace std;class UnionFind {public:vector<SINT64> parent;UnionFind(SINT64 N) {parent = vector<SINT64>(N+10, -1); //少し多めに}SINT64 root(SINT64 A) {if (parent[A] < 0) {return A;} else {parent[A] = root(parent[A]);return parent[A];}}SINT64 size(SINT64 A) {return parent[root(A)] * (-1);}bool judge(SINT64 A, SINT64 B) {A = root(A);B = root(B);if (A == B) {return true; //同じグループ} else {return false; //違うグループ}}void connect(SINT64 A, SINT64 B) {A = root(A);B = root(B);if (A != B) {if (size(A) < size(B)) {swap(A, B);}parent[A] += parent[B];parent[B] = A;}}};int main() {SINT64 N; cin >> N;SINT64 M; cin >> M;UnionFind uni(M);vector<vector<SINT64>> data(N);rep(i,0,N) {SINT64 a,b;cin >> a >> b;a--; b--;data[b].emplace_back(a);}SINT64 ans = 0;rep(i,0,N) {rep(j,1,data[i].size()) {if (uni.judge(data[i][0],data[i][j]) == false) {ans++;uni.connect(data[i][0],data[i][j]);}}}put(ans);return 0;}// vector<vector<SINT64>> data(N,vector<SINT64>(N)); //2次元配列// vector<vector<vector<SINT64>>> data(N,vector<vector<SINT64>>(N,vector<SINT64>(N))); //3次元配列// sort(data.begin(),data.end());// sort(data.begin(),data.end(),std::greater<SINT64>());// __gcd(A,B);// reverse(data.begin(),data.end());//関数へのvectorポインタ渡し//void dfs(SINT64 poi, SINT64 d, vector<vector<Pll>>& data) {//}/* 複数条件ソートbool sortcompare(Pll A, Pll B) {if(A.F == B.F){return A.S > B.S;} else {return A.F < B.F;}}sort(data.begin(),data.end(),sortcompare);*/// 二分探索/*SINT64 l,r,mid;l = 0;r = INF64;while( (r-l) > 1 ) {mid = (r-l)/2 + l;if (ok(mid) == 0) {r = mid;} else {l = mid;}}if (ok(r) == 1) {put(-1);} else {put(r);}*/// タプル//vector<tuple<SINT64,SINT64,SINT64>> edges;//edges.emplace_back(a,b,c);//cout << get<0>(edges[i]);//cout << get<1>(edges[i]);//cout << get<2>(edges[i]);//sort(begin(edges), end(edges)); //ソート// ソート後に使用 同じ値を消す// data.erase(std::unique(data.begin(), data.end()), data.end());// data.insert(data.begin() + X, 0); //X番目の要素に0を挿入// lower_boundは値がなければ最大値(.size())を返す// posi = lower_bound(data.begin(),data.end(), X) - data.begin(); // X以上を探す// posi = lower_bound(data.begin(),data.end(),make_pair(X,0)) - data.begin(); //pair/* 文字列回転string N;cin >> N;N = N[N.length()-1] + N.substr(0,N.length()-1);s = to_string(i); //ストリング変換*//* 文字列合成string N,M;cin >> N >> M;SINT64 ans = 0;ans = stoi(N+M);*//*//ワーシャルフロイドvector<vector<SINT64>> dist(N,vector<SINT64>(N,INF64));rep(i,0,N) {dist[i][i] = 0;}rep(k,0,N) {rep(i,0,N) {rep(j,0,N) {dist[i][j] = MIN(dist[i][j], dist[i][k]+dist[k][j]);}}}*//* 両端キューdeque<SINT64> data;data.emplace_front(buf); //先頭挿入*//* 優先度付きキューpriority_queue<SINT64, vector<SINT64>, greater<SINT64>> q; //小さいほうから取り出せるpriority_queue<SINT64, vector<SINT64>> q; //大きいほうから取り出せるq.push(X); //X を挿入q.top(); //先頭データ読みq.pop(); //先頭データ削除*//* キューqueue<SINT64> q; //宣言q.push(0); //挿入q.front(); //先頭データ読みq.pop(); //先頭データ削除*//* マルチセットmultiset<SINT64> mset;mset.insert(X); //追加auto it = mset.begin(); //先頭取得auto it = mset.rbegin(); //最後尾取得mset.erase(X); //削除(X全部)//削除 1個auto hit(mset.find(X));if (hit!= mset.end()) mset.erase(hit);*//* SET コンテナset<SINT64> data;data.insert(X); //X を挿入data.erase(data.begin()); //先頭を削除data.erase(--data.end()); //末尾を削除*data.begin(); //先頭要素にアクセス*data.rbegin(); //末尾要素にアクセス//全表示for(auto it = data.begin(); it != data.end(); it++) {cout << *it << " ";} cout << endl;//N番目を一部表示auto it = data.begin();rep (i,0,N) { it++; }cout << *it << endl;*//* mapmap<string,SINT64> mp;for(auto it=mp.begin();it!=mp.end();it++) {mx=max(mx,it->second);}*//*//順列全表示//sortしてからでないと全列挙にならないsort(data.begin(),data.end());do {cout << buf << endl;rep(i,0,R) {cout << data[i] << " ";}cout << endl;} while (next_permutation(data.begin(),data.end()));*//* bit数数え上げSINT64 bits64(SINT64 bits){bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555);bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333);bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f);bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff);return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff);}*///bitシフトのLONG対応// ans += (1L<<50);/* 余弦定理 2辺 A,B その間の角度からもう1辺を求めるlong double yogen(long double A, long double B, long double angle) {long double ans = A*A+B*B-A*B*2*cosl((PI/180.0)*angle);ans = sqrt(ans);return ans;}*/// 桁指定表示// ans = ans * M_PI;// cout << setprecision(15) << ans << endl;// 桁数0埋め// cout << std::setfill('0') << std::right << std::setw(2) << 5; //05//2次元累積和/*vector<vector<SINT64>> data(H,vector<SINT64>(W));vector<vector<SINT64>> rui(H+1,vector<SINT64>(W+1));rep(i,0,H) {rep(j,0,W) {cin >> data[i][j];}}rep(i,1,H+1) {rep(j,1,W+1) {rui[i][j] = data[i-1][j-1] + rui[i][j-1];}}rep(i,1,H+1) {rep(j,1,W+1) {rui[i][j] += rui[i-1][j];}}*/// 逆元 コンビネーション/*SINT64 modpow(SINT64 a, SINT64 p) {if (p == 0) return 1;if (p % 2 == 0) {//pが偶数の時SINT64 halfP = p / 2;SINT64 half = modpow(a, halfP);//a^(p/2) をhalfとして、half*halfを計算return half * half % MOD;} else {//pが奇数の時は、偶数にするために1減らすreturn a * modpow(a, p - 1) % MOD;}}SINT64 calcComb(SINT64 a, SINT64 b) {SINT64 Mul = 1;SINT64 Div = 1;SINT64 ans = 0;if (b > a - b) {return calcComb(a, a - b);}rep(i,0,b) {Mul *= (a - i);Div *= (i + 1);Mul %= MOD;Div %= MOD;}ans = Mul * modpow(Div, MOD - 2) % MOD;return ans;}*//* UNION FINDclass UnionFind {public:vector<SINT64> parent;UnionFind(SINT64 N) {parent = vector<SINT64>(N+10, -1); //少し多めに}SINT64 root(SINT64 A) {if (parent[A] < 0) {return A;} else {parent[A] = root(parent[A]);return parent[A];}}SINT64 size(SINT64 A) {return parent[root(A)] * (-1);}bool judge(SINT64 A, SINT64 B) {A = root(A);B = root(B);if (A == B) {return true; //同じグループ} else {return false; //違うグループ}}void connect(SINT64 A, SINT64 B) {A = root(A);B = root(B);if (A != B) {if (size(A) < size(B)) {swap(A, B);}parent[A] += parent[B];parent[B] = A;}}};UnionFind uni(N);*//* セグ木class SegTree {private:SINT64 size;vector<SINT64> node;SINT64 jugdement(SINT64 a, SINT64 b) {SINT64 ans = 0;ans = a+b;return ans;}public://コンストラクタSegTree(vector<SINT64> data) {SINT64 ori_size;ori_size = data.size();size = 1;while (size < ori_size) {size *= 2;}node.resize(2*size-1, 0);rep(i,0,ori_size) {node[size-1+i] = data[i];}rrep(i,size-2,0) {node[i] = jugdement(node[2*i+1], node[2*i+2]);}}//データ更新void update(SINT64 x, SINT64 val) {x += (size - 1);node[x] = val+node[x];while(x > 0) {x = (x - 1) / 2;node[x] = jugdement(node[2*x+1], node[2*x+2]);}}//データ取得 [a,b)SINT64 getdata(SINT64 a, SINT64 b, SINT64 k = 0, SINT64 l = 0, SINT64 r = -1) {if (r < 0) {r = size;}//要求範囲外if ((r <= a) || (b <= l)) {return 0;}//完全要求区間内if ((a <= l) && (r <= b)) {return node[k];}SINT64 vl = getdata(a, b, 2*k+1, l, (l+r)/2);SINT64 vr = getdata(a, b, 2*k+2, (l+r)/2, r);return jugdement(vl, vr);}};SegTree seg(N);*//* ダイクストラclass Dijkstra {vector<vector<Pll>> G;vector<SINT64> dist;public:Dijkstra(SINT64 n) {G.resize(n);dist.resize(n, INF64);}void add(SINT64 a, SINT64 b, SINT64 cost) {G[a].emplace_back(Pll(b,cost));}void clear(SINT64 n) {dist.resize(0);dist.resize(n,INF64);}void form(SINT64 s) {priority_queue<Pll, vector<Pll>, greater<Pll>> q;q.push(Pll(0,s)); //cost,位置while(q.size() != 0) {Pll now = q.top();q.pop();if (dist[now.S] == INF64) {dist[now.S] = now.F;rep(i,0,G[now.S].size()) {Pll buf = G[now.S][i];if (dist[buf.F] == INF64) {q.push(Pll(buf.S+now.F,buf.F));}}}}}//form()で構築したsからの距離を返すSINT64 get_dist(SINT64 a) {if (dist[a] == INF64) {return -1; //到達不可} else {return dist[a];}}};*//* LCAclass Lca {vector<vector<SINT64>> G;vector<vector<SINT64>> D; //ダブリングvector<SINT64> depth;SINT64 N;SINT64 LOG_N;public:Lca(SINT64 n) {N = n;LOG_N = floor(log2(N));G.resize(N);D.resize(N);depth.resize(N,-1);}void add(SINT64 a, SINT64 b) {G[a].emplace_back(b);G[b].emplace_back(a);}void bfs(SINT64 s) {depth[s] = 0;D[s].emplace_back(-1);queue<SINT64> q;q.push(s);while(q.size() != 0) {SINT64 now = q.front();q.pop();rep(i,0,G[now].size()) {SINT64 next = G[now][i];if (depth[next] == -1) {depth[next] = depth[now]+1;D[next].emplace_back(now);q.push(next);}}}}//頂点のsからのダブリング構築void form(SINT64 s) {bfs(s);rep(i,1,LOG_N+1) {rep(j,0,N) {SINT64 buf = D[j][i-1];if (buf == -1) {D[j].emplace_back(-1);} else {D[j].emplace_back(D[buf][i-1]);}}}}//aのx上の頂点を求めるSINT64 get(SINT64 a, SINT64 x) {rrep(i,LOG_N,0) {if (((x >> i) & 1) == 1) {a = D[a][i];if (a == -1) return -1;}}return a;}//aとbの共通祖先を求めるSINT64 get_lca(SINT64 a, SINT64 b) {if (depth[a] < depth[b]) swap(a,b);SINT64 diff = depth[a] - depth[b];a = get(a,diff); //aのx上の頂点を求めるif (a == b) return a;rrep(i,LOG_N,0) {if (D[a][i] != D[b][i]) {a = D[a][i];b = D[b][i];}}return D[a][0];}//aとbの共通祖先までの距離の合計を求めるSINT64 get_dist(SINT64 a, SINT64 b) {SINT64 buf = get_lca(a,b);return depth[a] + depth[b] - depth[buf]*2;}};*//* ベルマンフォードclass Bellman {struct EDGE {SINT64 from;SINT64 to;SINT64 cost;};vector<EDGE> edges;vector<SINT64> dist;SINT64 N;public:Bellman(SINT64 n) {N = n;dist.resize(n, INF64);}void add(SINT64 from, SINT64 to, SINT64 cost) {edges.emplace_back((EDGE){from,to,cost});}// sで構築したt迄の距離取得// 到達不可 : INF64// 負の閉路 : -INF64SINT64 get_dist(SINT64 t) {return dist[t];}// 構築// 到達不可 : INF64// 負の閉路 : -INF64SINT64 form(SINT64 s, SINT64 g) {dist[s] = 0;SINT64 cnt;cnt = 0;while(1) {SINT64 renew = 0;rep(i,0,edges.size()) {EDGE e = edges[i];if (dist[e.from] != INF64) {if (dist[e.to] > dist[e.from] + e.cost) {renew = 1;dist[e.to] = dist[e.from] + e.cost;}}}if (renew == 0) return dist[g]; // 負の閉路無しif (cnt > 2*N) break; // 負の閉路有りcnt++;}// 目的地gが負の経路の先にあるか調べるrep(ccc,0,N) {rep(i,0,edges.size()) {EDGE e = edges[i];if (dist[e.from] != INF64) {if (dist[e.to] > dist[e.from] + e.cost) {dist[e.to] = -INF64; // 更新があれば-INF64}}}}return dist[g];}};*//*コンビネーションclass Comb {vector<SINT64> base;SINT64 N;public:Comb (SINT64 n) {N = n+5;base.resize(N);base[0] = 1;rep(i,1,N) {base[i] = base[i-1]*i;base[i] %= MOD;}}SINT64 get_comb(SINT64 a, SINT64 b) {SINT64 ans = 0;SINT64 aa = base[a] * modpow(base[a-b], MOD - 2) % MOD;ans = aa * modpow(base[b], MOD - 2) % MOD;return ans;}SINT64 modpow(SINT64 a, SINT64 p) {if (p == 0) return 1;if (p % 2 == 0) {SINT64 halfP = p / 2;SINT64 half = modpow(a, halfP);return half * half % MOD;} else {return a * modpow(a, p - 1) % MOD;}}};*//* 転倒数の数え上げSINT64 merge_cnt(vector<SINT64> &a) {SINT64 n = a.size();if (n <= 1) { return 0; }SINT64 cnt = 0;vector<SINT64> b(a.begin(), a.begin()+n/2);vector<SINT64> c(a.begin()+n/2, a.end());cnt += merge_cnt(b);cnt += merge_cnt(c);SINT64 ai = 0, bi = 0, ci = 0;// merge の処理while (ai < n) {if ( bi < b.size() && (ci == c.size() || b[bi] <= c[ci]) ) {a[ai++] = b[bi++];} else {cnt += n / 2 - bi;a[ai++] = c[ci++];}}return cnt;}*//* 最長部分文字列SINT64 LCS(string s, string t) {SINT64 n = s.size();SINT64 m = t.size();vector<vector<SINT64>> DP(n+1,vector<SINT64>(m+1,0));rep(i,0,n) {rep(j,0,m) {if (s[i] == t[j]) {DP[i+1][j+1] = DP[i][j]+1;} else {DP[i+1][j+1] = MAX(DP[i+1][j],DP[i][j+1]);}}}return DP[n][m];}*//* トポロジカルソートclass Topological {vector<vector<SINT64>> child;vector<SINT64> parentct; // 入次数カウントSINT64 N;public:Topological(SINT64 n) {N = n;child.resize(n);parentct.resize(n,0);}void add(SINT64 from, SINT64 to) {child[from].emplace_back(to);parentct[to]++;}// sort 不可は size 0 を返すvector<SINT64> get_sort() {vector<SINT64> Tsort;queue<SINT64> q;rep(i,0,N) {if (parentct[i] == 0) {q.push(i);}}while(q.size() != 0) {SINT64 now = q.front();q.pop();rep(i,0,child[now].size()) {parentct[child[now][i]]--;if (parentct[child[now][i]] == 0) {q.push(child[now][i]);}}Tsort.emplace_back(now);if (Tsort.size() > N) break;}if (Tsort.size() != N) {vector<SINT64> Er;return Er;} else {return Tsort;}}};*/