codeforces 650E

原題

原題

題目大意

給你兩棵樹,你要讓原樹變爲新樹,每次可以刪一條邊加一條邊,但是在任意時刻,不能出現環,問最小步數以及刪邊加邊的方案。

解題思路

首先考慮那些在初態和終態下都出現的邊。這些邊顯然都是不動的,把它們連接的兩個點合併起來。合併時要維護這個集合內的點與集合外的點的連邊。

答案很顯然爲總邊數減去不動的邊數,即每次刪一條原樹中的邊,並增加一條終態的樹上的邊。

按照任意順序刪去原樹中要改變的邊(u,v) ,然後連一條從u 所在集合中的點到u 所在集合外的點的邊,以保證整個圖聯通。可以保證一定能找到這樣的邊。(證明?反證,如果沒有,那麼這個圖是不連通的)

參考代碼

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=500010;

struct Edge {int x,y;}Ed[maxn];

map <LL,int> M;

int head[maxn],next[maxn<<1],E[maxn<<1],Ecnt;
int Ehead[maxn],Enext[maxn<<1],Etail[maxn<<1],EE[maxn<<1],EEcnt;
int fa[maxn];
int n,m;

void Add_Edge(int x,int y) {
    next[++Ecnt]=head[x];
    head[x]=Ecnt;
    E[Ecnt]=y;
    next[++Ecnt]=head[y];
    head[y]=Ecnt;
    E[Ecnt]=x;
}
void Add_EdgeE(int x,int y,int p) {
    Enext[++EEcnt]=Ehead[x];
    if (Ehead[x]==0) Etail[x]=EEcnt;
    Ehead[x]=EEcnt;
    EE[EEcnt]=p;
    Enext[++EEcnt]=Ehead[y];
    if (Ehead[y]==0) Etail[y]=EEcnt;
    Ehead[y]=EEcnt;
    EE[EEcnt]=p;
}
int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);}

void DFS(int x,int father)
{
    for (int i=head[x];i;i=next[i]) if (E[i]!=father) DFS(E[i],x);
    if (x==1) return;
    if (Find(x)==Find(father)) return;
    int now=Ehead[Find(x)];
    while (Ehead[Find(x)] && Find(Ed[EE[now]].x)==Find(Ed[EE[now]].y)) 
        now=Ehead[Find(x)]=Enext[Ehead[Find(x)]];
    if (!now) return;
    int u=Ed[EE[now]].x,v=Ed[EE[now]].y;
    printf("%d %d %d %d\n",father,x,u,v);
    Enext[Etail[Find(u)]]=Ehead[Find(v)];
    Etail[Find(u)]=Etail[Find(v)];
    fa[Find(v)]=Find(u);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) fa[i]=i;
    for (int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        if (x>y) swap(x,y);
        M[(LL)x*n+y]=1;
        Add_Edge(x,y);
    }
    for (int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        if (x>y) swap(x,y);
        if (M[(LL)x*n+y]==1) {fa[Find(x)]=Find(y);continue;}
        Ed[++m].x=x,Ed[m].y=y;
    }
    for (int i=1;i<=m;i++) Add_EdgeE(Find(Ed[i].x),Find(Ed[i].y),i);
    printf("%d\n",m);
    DFS(1,0);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章