给定n个点的序列,一开始有n个块,每次将两个块合并,并告诉你这两个块中的一对元素,求一种可能的原序列
我们可以建立一个由多个二叉树组成的森林,并用并查集维护每个节点所在二叉树的根节点。
具体是这样的,如果当前是将\(x_{i},y_{i}\)所在的连通分量放在相邻的位置上,那么就将他们所在二叉树的根节点作为它们新的根节点。
然后在整个二叉树上进行dfs,得到的序列就是答案。
原理很显然,因为这样能保证一个非叶节点的左右儿子为相邻的连通分量。
#include<cstdio>
#define Rint register int
using namespace std;
const int N = 300003;
int n, cnt, fa[N], head[N], to[N << 1], nxt[N << 1];
inline void add(int a, int b){
static int cnt = 0;
to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
}
inline int getfa(int x){
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
inline void dfs(int u){
if(u <= n){printf("%d ", u); return;}
for(Rint i = head[u];i;i = nxt[i])
if(to[i] != fa[u]) dfs(to[i]);
}
int main(){
scanf("%d", &n); cnt = n;
for(Rint i = 1;i <= (n << 1);i ++) fa[i] = i;
for(Rint i = 1;i < n;i ++){
int a, b;
scanf("%d%d", &a, &b);
a = getfa(a); b = getfa(b);
add(++ cnt, a); add(cnt, b);
fa[cnt] = fa[a] = fa[b] = cnt;
}
dfs(cnt);
}