結果
問題 | No.1390 Get together |
ユーザー |
![]() |
提出日時 | 2021-02-12 21:47:29 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 4,587 bytes |
コンパイル時間 | 1,796 ms |
コンパイル使用メモリ | 173,336 KB |
実行使用メモリ | 18,524 KB |
最終ジャッジ日時 | 2024-07-19 20:57:39 |
合計ジャッジ時間 | 5,321 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 20 WA * 9 |
ソースコード
#include "bits/stdc++.h"//#include <atcoder/all>//using namespace atcoder;using namespace std;const int MAX = 700000;const int MOD = 1000000007;const long long INF = 1LL << 60;long long fac[MAX], finv[MAX], inv[MAX];// テーブルを作る前処理void COMinit() {fac[0] = fac[1] = 1;finv[0] = finv[1] = 1;inv[1] = 1;for (int i = 2; i < MAX; i++) {fac[i] = fac[i - 1] * i % MOD;inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;finv[i] = finv[i - 1] * inv[i] % MOD;}}// 二項係数計算long long COM(int n, int k) {if (n < k) return 0;if (n < 0 || k < 0) return 0;return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;}/*第二引数で第一引数を割ったときの切り上げの計算*/long long int maxtime(long long int x, long long int y) {return(x + y - 1) / y;}/*最大公約数*/long long int lcm(long long int number1, long long int number2) {long long int m = number1;long long int n = number2;if (number2 > number1) {m = number2;n = number1;}long long int s = -1;while (s != 0) {s = m % n;m = n;n = s;}return m;}/*最大公倍数*/long long int gcd(long long int number1, long long int number2) {long long int m = number1;long long int n = number2;return m / lcm(m, n) * n;}/*逆元計算*/long long int modinv(long long a, long long m) {long long int b = m, u = 1, v = 0;while (b) {long long int t = a / b;a -= t * b; swap(a, b);u -= t * v; swap(u, v);}u %= m;if (u < 0) u += m;return u;}long long mod(long long val, long long m) {long long res = val % m;if (res < 0) res += m;return res;}//セグメントツリー(あってるかはわからんから自己責任で)const int MAX_N = 10000000;//セグメント木を持つグローバル配列int n,dat[2*MAX_N - 1];//初期化void init(int n_){//簡単のため,要素数を2のべき乗にn = 1;while(n < n_) {n *= 2;}//すべての値をINT_MAXにfor(int i = 0; i < 2 * n - 1; i++){//dat[i] = INT_MAX;dat[i] = 0;}}// k番目の値(0-indexed)をaに変更void update(int k,int a){//葉の節点k += n - 1;dat[k] = a;//登りながら更新while(k > 0){k = (k - 1) / 2;dat[k] = max(dat[k * 2 + 1], dat[k * 2 + 2]);}}// [a, b)の最小値を求める// 後ろのほうの引数は,計算の簡単のための引数//kは節点の番号, l, rはその節点が[l, r)に対応づいていることを表す。// したがって,外からはquery(a, b, 0, 0, n)として呼ぶ.int query(int a, int b, int k = 0, int l = 0, int r = n){// [a, b)と[l, r)が交差しなければ,INT_MAXif (r <= a || b <= l){return 0;}// [a, b)が[l, r)を完全に含んでいれば,この節点の値if (a <= l && r <= b){return dat[k];}else{//そうでなければ,2つの子の最小値int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);return max(vl,vr);}}//Union-Find アッカーマン関数よくわからないint par[MAX_N]; //親int ranks[MAX_N]; //木の深さ//n要素で初期化void initunion(int n){for(int i = 0;i < n;i++){par[i] = i;ranks[i] = 0;}}//木の根を求めるint find(int x){if (par[x] == x){return x;}else{return par[x] = find(par[x]);}}//xとyの属する集合を併合void unite(int x,int y){x = find(x);y = find(y);if(x == y){return;}if(ranks[x] < ranks[y]){par[x] = y;}else{par[y] = x;if(ranks[x] == ranks[y]){ranks[x]++;}}}//xとyが同じ集合に属するか否かbool same(int x,int y){return find(x) == find(y);}vector<vector<long long int >>G(200030);int main(){long long int n,m;cin >> n >> m;for(long long int i = 0;i < n;i++){long long int b,c;cin >> b >> c;b--;c--;G[c].push_back(b);}initunion(n);long long int ans = 0;for(long long int i = 0;i < n;i++){for(long long int j = 1;j < G[i].size();j++){if(!(same(G[i][j],G[i][j-1]))){ans++;unite(G[i][j],G[i][j-1]);}}}cout << ans <<endl;}