[agc14e]Blue and Red Tree

来源:互联网 发布:zola算法美队2 编辑:程序博客网 时间:2024/05/14 20:50

前言

这题主要是要想到倒过来,是一个很唯一的过程。
我大概想到了,但我比题解蠢。
题解的不需要区分红蓝让我觉得很机智。

题意

有一颗全是蓝边的树,你对其执行n-1次操作。
每次操作选择一条全是蓝边的路径,将其中的一条蓝边断开,假设选择的路径是j->k,断的边是x-y,且断开后j和x联通,那么k和y联通。
然后你需要选择j->x上的一个节点,以及k->y上的一个节点,在这两个节点间连红边。
现在问你能否存在方案变着指定的全是红边的树。

题解

考虑倒过来加边。
这个过程是很唯一的。
首先一开始有很多单点联通块。
每次如果两个联通块之间存在蓝边与红边相连,合并两个联通块。
最后合并成一个就行了。
好实现的方法是,这个红和蓝我们可以认为没有区别。
于是可以用一个queue存需要合并的联通块对(即之间存在两条边),用map来存两个联通块间的边数,用set存与某个联通块存在边的联通块,用并查集来维护连通性,合并两个联通块只需要启发式合并即可。
这样真好写!

#include<cstdio>#include<algorithm>#include<set>#include<map>#include<queue>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100000+10;typedef pair<int,int> pi;pi zlt;map<pi,int> cnt,bz;set<int> s[maxn];set<int>::iterator it;queue<pi> dl;int fa[maxn];int i,j,k,l,t,n,m,x,y,z,ca;bool czy;int getfa(int x){    return fa[x]?fa[x]=getfa(fa[x]):x;}int main(){    scanf("%d",&n);    fo(i,1,2*(n-1)){        scanf("%d%d",&j,&k);        if (j>k) swap(j,k);        zlt=make_pair(j,k);        cnt[zlt]++;        if (cnt[zlt]==1){            s[j].insert(k);            s[k].insert(j);        }        if (cnt[zlt]>1&&!bz[zlt]){            dl.push(zlt);            bz[zlt]=1;        }    }    czy=1;    ca=n-1;    while (ca--){        x=y=-1;        while (!dl.empty()){            j=getfa(dl.front().first);            k=getfa(dl.front().second);            dl.pop();            if (j!=k){                x=j;y=k;                break;            }        }        if (x==y&&x==-1){            czy=0;            break;        }        if (s[x].size()<s[y].size()) swap(x,y);        fa[y]=x;        it=s[y].begin();        while (it!=s[y].end()){            z=*it;            it++;            s[z].erase(s[z].find(y));            if (z==x) continue;            //if (s[x].find(z)==s[x].end()) s[x].insert(z),s[z].insert(x);            if (x<z) zlt=make_pair(x,z);else zlt=make_pair(z,x);            cnt[zlt]++;            if (cnt[zlt]==1){                s[x].insert(z);                s[z].insert(x);            }            if (cnt[zlt]>1&&!bz[zlt]){                dl.push(zlt);                bz[zlt]=1;            }        }        s[y].clear();    }    if (czy) printf("YES\n");else printf("NO\n");}