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