[NOI 2001]食物連鎖
6174 ワード
[NOI 2001]食物連鎖
問題の大意は必ず読めるが、どうすればいいかは問題だ.私の方法は権力を持ってセットを調べることです.まず、rと父(根)の関係を表す配列rをもう一つ追加することができます.コードを見ればわかります.
実はもう一つの方法は、どうせ私たちはすべての動物がA、Bに属しているのかCに属しているのか分からないので、私たちはすべての状況について考えています(3倍の空間を開けます).1操作と仮定すると,入力されたxとyは,各種類のxとをつなぎ合わせて1つの集合(そして集合を調べる)となり,2操作であれば3つのケース:1,xがA yでB 2,xがB yでC 3,xがC yでAをそれぞれつなぎ合わせて矛盾を判断するのは簡単である.コードを見て
この問題をやり終えて、また調査集に対する理解が深まったような気がします.
問題の大意は必ず読めるが、どうすればいいかは問題だ.私の方法は権力を持ってセットを調べることです.まず、rと父(根)の関係を表す配列rをもう一つ追加することができます.コードを見ればわかります.
#include //a==fa[a] 0 a -> fa[a] 1 a
using namespace std; // r , 0 , 1 , 2 。
int fa[100005],r[100005],ans,n,m;
int get(int x){
if(fa[x]==x) return x;
int y=fa[x];//
fa[x]=get(fa[x]);//
r[x]=(r[y]+r[x])%3;//
return fa[x];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
for(;m--;){
int c,x,y;
scanf("%d%d%d",&c,&x,&y);
if(x>n||y>n) ans++;
else
{
int xx=get(x),yy=get(y);
if(xx==yy){
if(c==1&&r[x]!=r[y]) ans++;//
if(c==2&&(r[x]==r[y]||(r[y]+1)%3==r[x])) ans++;//
}
else {
fa[xx]=yy;//
if(c==1) r[xx]=(r[y]-r[x]+3)%3;
else r[xx]=(r[y]-r[x]+2)%3;
}
}
}
printf("%d",ans);
return 0;
}
実はもう一つの方法は、どうせ私たちはすべての動物がA、Bに属しているのかCに属しているのか分からないので、私たちはすべての状況について考えています(3倍の空間を開けます).1操作と仮定すると,入力されたxとyは,各種類のxとをつなぎ合わせて1つの集合(そして集合を調べる)となり,2操作であれば3つのケース:1,xがA yでB 2,xがB yでC 3,xがC yでAをそれぞれつなぎ合わせて矛盾を判断するのは簡単である.コードを見て
#include
using namespace std;
int fa[3*100005],n,m,ans;
int get(int x){
return x==fa[x]? x:(fa[x]=get(fa[x]));//
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=3*n;i++) fa[i]=i;
for(;m--;){
int c,x,y;
scanf("%d%d%d",&c,&x,&y);
if(x>n||y>n) ans++;//
else
if(c==1){
if(get(x+n)==get(y)||get(x)==get(y+n)) ans++;// x y y x
else fa[get(x)]=fa[get(y)],fa[get(x+n)]=fa[get(y+n)],fa[get(x+2*n)]=fa[get(y+2*n)];//
}
else{
if(get(x)==get(y)||get(x+n)==get(y)) ans++; // x y x y
else fa[get(x)]=fa[get(y+n)],fa[get(x+n)]=fa[get(y+2*n)],fa[get(x+2*n)]=fa[get(y)];// +1
}
}
printf("%d",ans);
return 0;
}
この問題をやり終えて、また調査集に対する理解が深まったような気がします.