1. 程式人生 > >AT2377 Blue and Red Tree

AT2377 Blue and Red Tree

題目
題解

Solution

首先可以發現最終狀態替換的紅邊和藍邊一定是重邊。把這條邊兩端的聯通塊看成一個點。
往回推,要形成這兩個點,必須也要有類似的重邊
這樣就可以得到一種做法。每次把重邊兩端的放入佇列,並把邊集合並(啟發式合併),把這兩個聯通塊合併
再把重邊放入,直至更新完成

Code

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
const int N=100001;
int fa[N],h,t,u,v,s,n,i,to;
set<int>S[N];
set<
int>::iterator it; map<pair<int,int>,int>ma; pair<int,int>q[N]; inline char gc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd(){ int x=0,fl=1;char ch=gc(); for (;ch<48||ch>57;ch=gc())if(
ch=='-')fl=-1; for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48); return x*fl; } inline void wri(int a){if(a<0)a=-a,putchar('-');if(a>=10)wri(a/10);putchar(a%10|48);} inline void wln(int a){wri(a);puts("");} int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } int
main(){ n=rd(); for (i=1;i<=2*n-2;i++){ u=rd();v=rd(); S[u].insert(v);S[v].insert(u); ma[mp(u,v)]++,ma[mp(v,u)]++; if (ma[mp(u,v)]==2) q[t++]=mp(u,v); } for (i=1;i<=n;i++) fa[i]=i; while (h<t){ u=find(q[h].first),v=find(q[h++].second); S[u].erase(v);S[v].erase(u); if (S[u].size()<S[v].size()) swap(u,v); for (it=S[v].begin();it!=S[v].end();it++){ to=*it; S[to].erase(v); ma[mp(v,to)]=ma[mp(to,v)]=0; S[u].insert(to);S[to].insert(u); ma[mp(u,to)]++;ma[mp(to,u)]++; if (ma[mp(u,to)]==2) q[t++]=mp(u,to); } fa[v]=u;S[v].clear(); } for (i=1;i<=n;i++) s+=fa[i]==i; puts(s==1?"YES":"NO"); }