Loading

【题解】CF650E-Clockwork Bomb

给定两棵树 \(A,B\),每次先删除 \(A\) 一条边,再加入 \(A\) 一条边,过程中不能成环,现在构造一个方案用最少次操作将 \(A\) 变成 \(B\)

显然两棵树中都存在的边可以不用删,我们将这些边留下,将每个连通块缩成一个点。

那么我们得到两颗大小相同的新树,且不存在一条边在两棵树内都出现。

考虑从叶子开始删除,每次删除一个叶子与其父节点的边,然后连上需要还原的 \(B\) 边。操作完成后叶子的父边算是还原了,就可以直接将叶子删除。由于每次删除都是分裂出一个节点,再把这个节点接回去,所以是正确的。

时间复杂度 \(\mathcal{O}(N)\)

#define N 500005
struct Tree{
	vector<int>e[N]; int fa[N];
	void dfs(int x,int f){fa[x] = f; go(y, e[x])if(y != f)dfs(y, x);}
}A, B;
int n, fa[N];
int get(int x){return fa[x] == x ? x : fa[x] = get(fa[x]);}
struct node{int x, y, a, b;};
vector<node>ed;
void dfs(int x,int f){
	go(y, A.e[x])if(y != f){
		dfs(y, x);
		if(fa[y] != fa[x])ed.pb(node{x, y, fa[y], B.fa[fa[y]]});
	}
}
int main() {
	read(n);
	rp(i, n - 1){
		int x, y; read(x, y);
		A.e[x].pb(y), A.e[y].pb(x);
	}
	rp(i, n - 1){
		int x, y; read(x, y);
		B.e[x].pb(y), B.e[y].pb(x);
	}
	A.dfs(1, 0), B.dfs(1, 0);
	rp(i, n)fa[i] = i;
	rep(x, 2, n){
		int y = B.fa[x];
		if(A.fa[x] == y || A.fa[y] == x)fa[x] = y;
	}
	rp(i, n)get(i);
	dfs(1, 0);
	printf("%d\n", si(ed));
	go(x, ed)printf("%d %d %d %d\n", x.x, x.y, x.a, x.b);
	return 0;
}
posted @ 2022-05-17 22:24  7KByte  阅读(45)  评论(0编辑  收藏  举报