题意:
给出两棵树,要求将第一棵变成第二棵。可以进行的操作是删除一条边,再加入一条边。要求每次操作后仍是一棵树。问最小操作次数和方案。
n<=500000
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<vector>
#define N 510000
#define pb push_back
using namespace std;
struct node{int y,rx,ry,nex;}a[2*N];
vector<int> v1[N],v2[N];
int n,fir[N],len,fa[N],fr[N][2],rt,A[N][4],num;
bool b[N];
void ins(int x,int y,int rx,int ry)
{
a[++len].y=y;a[len].rx=rx;a[len].ry=ry;a[len].nex=fir[x];fir[x]=len;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int x,int y)
{
fa[find(x)]=find(y);
}
void dfs(int x,int fa)
{
for(int k=fir[x];k;k=a[k].nex)
{
int y=a[k].y;
if(y==fa) continue;
fr[y][0]=a[k].rx;fr[y][1]=a[k].ry;
dfs(y,x);
}
}
void dfs1(int x,int fa)
{
for(int k=fir[x];k;k=a[k].nex)
{
int y=a[k].y;
if(y==fa) continue;
A[++num][0]=fr[y][0];A[num][1]=fr[y][1];A[num][2]=a[k].rx;A[num][3]=a[k].ry;
dfs1(y,x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
v1[x].pb(y);v1[y].pb(x);
}
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
v2[x].pb(y);v2[y].pb(x);
}
for(int i=1;i<=n;i++) fa[i]=i;
for(int x=1;x<=n;x++)
{
int s1=v1[x].size(),s2=v2[x].size();
for(int j=0;j<s1;j++) b[v1[x][j]]=1;
for(int j=0;j<s2;j++) if(b[v2[x][j]]) merge(x,v2[x][j]);
for(int j=0;j<s1;j++) b[v1[x][j]]=0;
}
for(int x=1;x<=n;x++)
{
int siz=v1[x].size();
for(int j=0;j<siz;j++)
{
int y=v1[x][j];
if(find(x)!=find(y)) ins(fa[x],fa[y],x,y);
}
}
rt=fa[1];
dfs(rt,0);
len=0;
for(int i=1;i<=n;i++) fir[i]=0;
for(int x=1;x<=n;x++)
{
int siz=v2[x].size();
for(int j=0;j<siz;j++)
{
int y=v2[x][j];
if(find(x)!=find(y)) ins(fa[x],fa[y],x,y);
}
}
dfs1(rt,0);
printf("%d\n",num);
for(int i=1;i<=num;i++) printf("%d %d %d %d\n",A[i][0],A[i][1],A[i][2],A[i][3]);
}
题解:
先把对的边缩起来,然后以1为根建出两棵树,这个时候所有边都是错的了。
假设现在有n个点,显然答案下界是n-1。
考虑这样构造:
维护两个集合A,B。初始A为{1},B为{2…n}。
A,B时刻满足如下性质
1、A中的点之间的边是对的
2、只考虑A中的边,A内部是联通的
3、B中的点直接联通,或通过与A有关的边间接联通
4、整个图是一棵树
假设向A中加入一个新点x,这个点和已在A中的y在第二棵树中有边。
此时需要删除x的一条边,然后加入(x,y)。
我们在第一棵树上把A中的点标为红色
那么容易发现,删除第一棵树上x到父亲的边一定正确。
这样,就构造出了答案的下界。
于是模拟即可。