Noip 2019合宿テスト試合(二十一)Problem B:赤と青の木
5980 ワード
Noip 2019合宿テスト試合(二十一)Problem B:赤と青の木
Description
一本ある
N個の点、頂点番号が1からNの木.N−1辺のi番目の辺は頂点aiとbiを接続する.各エッジは、最初に青に染められます.高橋君はN−1回操作して、この青い木を赤い木に変えます.*青いエッジのみを含む単純なパスを選択し、これらのエッジの1つを削除します.*次に、パスの2つの端点の間に赤いエッジが接続されます.彼の目標は、iごとにciとdiを接続する赤いエッジがあることです.今、彼の目標を達成できるかどうかを判断してください.
Input
タイトルデータは下記の形式で標準入出力から入力します.
NNa1 b1⋮aN−1 bN−1c1 d1⋮cN−1 dN−1
Output
もし目標が達成できるならば、出力`YES`を出して、さもなくば出力`NO`を出します.
Sample Input
sample input 1:
3
1 2
2 3
1 3
3 2
sample input 2:
5
1 2
2 3
3 4
4 5
3 4
2 4
1 4
1 5
sample input 3:
6
1 2
3 5
4 6
1 6
5 1
5 3
1 4
2 6
4 3
5 6
Sample Output
sample output 1:
YES
sample output 2:
YES
sample output 3:
NO
HINT
サンプル1:目標達成可能:
*まず、頂点の接続を選択します.
1~33のエッジを削除し、1~2の間の青いエッジを除去し、1~3の間に赤いエッジを生成します.*次に、頂点2と3を接続するエッジを選択し、2と3の間の青いエッジを削除し、2と3の間に赤いエッジを生成します.
*2≦N≦105*1≦ai,bi,ci,di≦N*ai≠bi*ci≠di*入力の2つの図はツリーです.
解析:
赤い木を青い木に変えることができれば、N-2のエッジを変えた後、最後の青いエッジが最後の赤いエッジと重なることはありません.
この重なり合うエッジは、以前のすべてのエッジで任意に使用できます.
では、元のツリーのそれぞれの赤で青のエッジの2つの端点を1つの点に縮めることができます(元の接続されたエッジを削除し、1つの点のすべてのエッジを別の点に移動し、啓発的に結合して点を縮めることができます).
最終的に木全体を一つの点に縮めることができれば、YESであり、そうでなければNOである.
イニシアチブマージの総消費時間はO(nlogn)
アルゴリズム全体の時間的複雑さはO(nlogn)である.
#include
#include
#include<set>
using namespace std;
struct data{
int x,y;
}t[200001];
int n,m,f[200001],x,y,cnt;
set<int> v[200001];
int fa(int a){
if(f[a]!=a)f[a]=fa(f[a]);
return f[a];
}
void ins(int a,int b){
set<int>::iterator id1=v[a].find(b),id2=v[b].find(a);
if(id1==v[a].end()){
v[a].insert(b);
v[b].insert(a);
}else{
cnt++;
v[a].erase(b);
v[b].erase(a);
t[cnt].x=a;
t[cnt].y=b;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n*2-2;i++){
scanf("%d%d",&x,&y);
ins(x,y);
}
for(int i=1;i<=n;i++)f[i]=i;
while(cnt){
x=fa(t[cnt].x);
y=fa(t[cnt].y);
cnt--;
if(v[x].size()>v[y].size())swap(x,y);
f[x]=y;
for(int i:v[x]){
v[i].erase(x);
ins(i,y);
}
v[x].clear();
m++;
}
if(m==n-1)printf("YES
");
else printf("NO
");
}