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 件のコメント:
コメントを投稿