P2024の食物連鎖(互いに素セットのようなもの)

P2024 [NOI2001]食物連鎖

タイトル説明

動物界のAの動物の3種類があり、Bは、Cは、動物の食物連鎖の3つのタイプが面白い環を構成します。食品B、BはAを食べるC、Cを食べます
動物の前N、1 -のID N. 各動物は親切でA、B、Cであるが、我々は最終的にはそれを知らないどのような種類のです。
一部の人々は、2種類の方法によって形成され、この関係N動物の食物連鎖について説明します。

  • 最初の引数が「1 XY」であり、X及びYは類似している表します。
  • 第2引数は「2 XY」であり、XはYを食べる表します

上記の二つの文、文によって、一つの文章とNの動物のためのこの人は、この文いくつかの真の、いくつかの偽のK、Kを避けます。以下の三つの言葉の一つ、この文は嘘である場合には、真実はそうです。

  • 真の現在および以前の紛争のいくつかは、それから、嘘である場合
  • Nよりも、現在のXまたはYの大きい、その嘘の場合
  • 現在のX Xは、嘘であると言って食べて

タスクは、N及びKの単語の総数、嘘の出力に応じて与えられます。

入力形式

二つの整数の最初の行、N、K、Nは、Kワードを動物発現しました。
各ラインのワードの2行目

出力フォーマット

ライン、嘘の合計数を表す整数。


使用にばらばらセットの古典的な種類

加重互いに素-セットと呼ばれているように見える
ので、互いに素-セットは単純なことではないと感じ

我々は、缶と記録し、各要素の焦点を確認し(\)の関係(X)を\表す\(X \)\(FA(X)\)の関係
\(関係式(X)\)がある3つの値:

  • 0を示している\(X \)\(FA(x)は\)と同じです
  • 1、それは示している\(Xが\)である(\ FA(X))\食べ
  • 図2 \(X \)食べ\(FA(X)\)

もちろん、自分の父親の各ノードの時間の始まり(\関係では)\ 0で、彼自身と彼の親切です

更新され、圧縮されたときに、私たちはパスを運んでいる(FA(x)は\)\同時に、あなたは更新する必要があります\(関係(X)\)
私たちが知っていることを考える\(関係(x)は、関係 (FA(X ))\) どのように終了します\()は、x \とその関係おじいちゃんの?
すなわち:\((関係における関係(X-)+(FA(X-)))\ BMOD 3 \で)
知っしようとすると、それぞれのケースのために設立され、怠惰は書き出すていないので
、実際は説明に、3つの値が記述方法によれば、これら3つの値の有意性を決定するために、上記の単純な式に、撮影しただけランダムではありません

その後、別の事、考える\(関係(X)\)です\(X \) その後どのように、親の情報に対する\(関係(X)\)を取得するとその父親にそれを情報を?
、3例を知ることを試みる\((3-関係(X
))\ BMOD 3 \) のような、わずかに例えば\(X \)食べることができ(FA(X)\)\すなわち、\ (関係式(X)= 2 \
) 次に\(3-関係(X)= 1 \)ことを示し、\(FA(X)が\)である\(X \)食べ

これにより、2組のマージする方法を検討することが可能となる
設定\(X、Yを\)根がある(のfind_xx、Findy \)\、そして、私たちは聞かせて(FA(findy)= findx \
\) その後、\(FA(findy)\)に更新され、その後、\(関係(findy)\)も更新がします
コードに対してコードを入れては比較的簡単なはずと言います

inline void link(int x,int y,int findx,int findy,int o){
	fa[findy]=findx;
	relation[findy]=(3-relation[y]+o-1+relation[x])%3;
}

つまりo、文のタイプである\(O = 1 \)同じ種を表し、\(O = 2 \)ことを表し(X \)\食べる(Y \)\
この一つの単語が完了した後もかかわらず、他のノードが省略されています

知っている\(findx \)及び(findy \)\確かから、関係を(X、Y \)\他のノードとの間には関係がないので、開始するエッジを接続不明である
\(O-1 \) すなわち\(Y \)相対に対して)X(\ \関係、換言すれば、\(Y \)\(X \) そう=(関係(Y \) O-1は、\)
我々は、元の木に父親の息子によって指示されている青色のエッジ下図のあるいくつかのエッジを、想像することができます

要件バインドする前に言った\(xと\)の関係おじいちゃんの方法に関して、我々はより深いと相まって、このメソッドを与えることができます
求めている\(findy \)をその父の父の父の(((に関して関係
事実を、その後、3ので行って、戻って青色の矢印に従うものは、に行ってきました\(findx \)
生成された後、3つのセグメント青い矢印\(リレーション\)の値は、ライン上の3ダイまで追加
これも反映巧妙な方法で決定\(関係\)それは決定盲目であれば、単純な公式はありませんどのように重要な価値、そして二段階は、幸いなことに、このステップは3つに非常に厄介になっ
ているので\ ((3-関係(Y))+(1-O)+関係(X)\ BMOD。3 \) 順序が矢印の方向にカウンタであります

この質問は基本的には、いくつかの詳細は、コードだけで罰金を見て明確なので
、しかし、話の実現上の場所があり、あるfind機能

int find(int x){
	if(fa[x]==x) return x;
	int tmp=fa[x];
	fa[x]=find(fa[x]);
	relation[x]=(relation[x]+relation[tmp])%3;
	return fa[x];
}

なぜ最初にfa[x]=find(fa[x])更新した後relation[x]
プロセスがあるのでfa[x]、それを使用した場合の前に、relation[fa[x]]更新にrelation[x]は、時間のfa[x]ルーツとの関係は、エラーメッセージが更新されない場合があり、更新に使用することはできませんrelation[x]

なぜの定義すべきtmp=fa[x]
そのためfa[x]=find(fa[x])fa[x]値が変更されました

だから、チェックは、それ自体で、この事は難しいようではありませんが、より高度なアプリケーションのいくつかは、まだの何か持っている設定
はもちろん理由は、私があまりにもこんにゃくました

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	int x=0,y=1;
	char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m;
int fa[50006],relation[50006];
inline void link(int x,int y,int findx,int findy,int o){
	fa[findy]=findx;
	relation[findy]=(3-relation[y]+o-1+relation[x])%3;
}
int find(int x){
	if(fa[x]==x) return x;
	int tmp=fa[x];
	fa[x]=find(fa[x]);
	relation[x]=(relation[x]+relation[tmp])%3;
	return fa[x];
}
int main(){
	n=read();m=read();
	reg int ans=0;
	for(reg int i=1;i<=n;i++) fa[i]=i;
	for(reg int i=1,o,x,y;i<=m;i++){
		o=read();x=read();y=read();
		if(x>n||y>n){ans++;continue;}
		if(o==2&&x==y){ans++;continue;}
		int findx=find(x),findy=find(y);
		if(findx!=findy) link(x,y,findx,findy,o);
		else{
			if(o==1){if(relation[x]!=relation[y]) ans++;}
			else{
				if((relation[y]+3-relation[x])%3!=1) ans++;
			}
		}
	}
	std::printf("%d",ans);
	return 0;
}

おすすめ

転載: www.cnblogs.com/suxxsfe/p/12595969.html