http://poj.org/problem?id=1182
動物がN匹いて、1..Nの番号が振られている。
動物はA,B,Cの3種に分けられ、A->B->C->Aの強弱関係。
次の2種類の情報が順番にk個与えられる。
- xはy同じ種類
- xはyを食べる
ただし矛盾した情報はその場で捨て、以降考慮しないで良い。
アリ本p85より。Union-Find木を使います。
A,B,C用の配列を作ったらダメだし...と明後日の方向を見つめていた為、init(N*3)に目から鱗でした。
ただ、感動した割にpar[MAX_N*3]としないで弾かれるあたりが限界です。
最大入力数が10万と大きいため、cinを使うと弾かれます。
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <functional> #include <algorithm> #define MAX_N 50001 #define MAX_K 100001 #define DBG 0 using namespace std; int par[MAX_N*3]; int rank[MAX_N*3]; int N,K; int T[MAX_K],X[MAX_K],Y[MAX_K]; // n要素で初期化 void init(int n){ for(int i = 0; i < n; i++){ par[i] = i; rank[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 (rank[x] < rank[y]){ par[x] = y; } else{ par[y] = x; if(rank[x] == rank[y]){ rank[x] += 1; } } } // xとyが同じ集合に属するか否か bool same(int x, int y){ return find(x) == find(y); } void solve(){ init(N*3); int ans = 0; for(int i = 0; i < K; i++){ int t = T[i]; int x = X[i] - 1, y = Y[i] - 1; if(x < 0 || N <= x || y < 0 || N <= y){ ans += 1; if(DBG){ cout << i << endl; } continue; } if(t == 1){ if(same(x, y+N) || same(x, y+2*N)){ ans += 1; if(DBG){ cout << i << endl; } } else{ unite(x, y); unite(x+N, y+N); unite(x+2*N, y+2*N); } } else{ if(same(x, y) || same(x, y+2*N)){ ans += 1; if(DBG){ cout << i << endl; } } else{ unite(x, y+N); unite(x+N, y+2*N); unite(x+2*N, y); } } } cout << ans << endl; } int main(){ cin >> N >> K; for(int i = 0; i < K; i++){ scanf("%d %d %d", &T[i], &X[i], &Y[i]); } solve(); return 0; }
0 件のコメント:
コメントを投稿