Codeforces Round #345 (Div. 1) E Clockwork Bomb

非常好的一道題

首先很容易想到當你拆一條邊後加邊的次序是隨意的

然後我們可以這麼想:如果在兩個圖中都存在的邊沒有任何意義,所以我們可以在結果圖中先把相同邊留下,把其他邊刪去,怎麼弄呢,如果是一棵樹就好辦了,所以剩下就是把一堆樹連起來。然後考慮開始的圖,對於在結束圖中不存在的邊我們把它也刪了,然後就是從當前節點出發有聯通快,這些聯通塊在第二張圖裏面也存在,所以下面很簡單了,我們只要把當前聯通塊的祖先與它在結果圖中的父親練一下就好了,那麼餓會不會重複呢?不可能,因爲在原圖中它是一棵樹,所以對於一個點不可能有兩個父親,而每次連邊的時候只從兒子開始找

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define mp(a,b) make_pair(a,b)
#define xx first
#define yy second
using namespace std;
const int maxn=500005;
vector<int>g[2][maxn];
int fa[2][maxn];
int pp[maxn];
typedef pair<int,int>p1;
typedef pair<p1,p1>p2;
vector<p2> gg;
int find(int p){
    if(pp[p]==-1||pp[p]==p) return pp[p]=p;
    return pp[p]=find(pp[p]);
}
int panduan(int u,int x,int y){
    if(fa[u][x]==y||fa[u][y]==x) return 1;
    return 0;
}
void dfs(int u,int p,int pa){
    fa[u][p]=pa;
    for(int v:g[u][p]){
        if(v==pa) continue;
        dfs(u,v,p);
    }
}
void solve(int u,int pa){
    for(int v:g[0][u]){
        if(v!=pa){
            solve(v,u);
            if(!panduan(1,u,v)){
                int w=find(v);
                gg.push_back(mp(mp(u,v),mp(w,fa[1][w])));
            }
        }
    }
}
int main()
{
    int i,n;
    cin>>n;
    for(i=0;i<n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        g[0][x].push_back(y);
        g[0][y].push_back(x);
    }
    for(i=0;i<n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        g[1][x].push_back(y);
        g[1][y].push_back(x);
    }
    dfs(0,1,-1);
    dfs(1,1,-1);
    memset(pp,-1,sizeof(pp));
    for(i=2;i<=n;i++){
        if(panduan(0,i,fa[1][i])){
            pp[i]=fa[1][i];
        }
    }
    solve(1,-1);
    int p=gg.size();
    printf("%d\n",p);
    for(i=0;i<p;i++){
        printf("%d %d %d %d\n",gg[i].xx.xx,gg[i].xx.yy,gg[i].yy.xx,gg[i].yy.yy);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章