用并查集构造一颗树即可。
关键在于fa()中的合并路径,更新父节点,但不更新子节点。
方法1,速度较快,内存占用小,不直观:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 150015
int n;
int num[maxn*2][3]; // fa c1 c2
int cnt;
int fa(int a){
int b = a;
while(num[b][0]!=b){
b = num[b][0];
}
while(num[a][0]!=b){
int c = num[a][0];
num[a][0] = b;
a = c;
}
return b;
}
void solve(int a,int b){
int af = fa(a);
int bf = fa(b);
num[af][0] = cnt;
num[bf][0] = cnt;
num[cnt][1] = af;
num[cnt][2] = bf;
cnt++;
}
void print(int a){
int c1 = num[a][1];
int c2 = num[a][2];
if(c1<=n) printf("%d ",c1);
else print(c1);
if(c2<=n) printf("%d ",c2);
else print(c2);
}
void tprint(){
for(int i=1;i<10;i++){
printf("%d %d %d %d\n",i,num[i][0],num[i][1],num[i][2]);
}
}
int main(){
scanf("%d",&n);
memset(num,0,sizeof(num));
for(int i=1;i<=2*n;i++) num[i][0] = i;
cnt = n + 1;
for(int i=0;i<n-1;i++){
int a,b;
scanf("%d%d",&a,&b);
solve(a,b);
//tprint();
}
print(cnt-1);
printf("\n");
return 0;
}
方法2,速度较慢,内存占用多,直观:
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 150015
int n;
int fa[maxn];
vector<int> cld[maxn];
int f(int a){
int b = a;
while(fa[a] != a){
a = fa[a];
}
while(fa[b] != a){
int c = fa[b];
fa[b] = a;
b = c;
}
return a;
}
void solve(int a,int b){
int af = f(a);
int bf = f(b);
int cf = af;
af = min(af,bf);
bf = max(cf,bf);
cld[af].insert(cld[af].end(), cld[bf].begin(), cld[bf].end());
fa[bf] = af;
}
void print(){
for(int i=1;i<=n;i++){
for(vector<int>::iterator p = cld[i].begin();p!=cld[i].end();p++){
printf("%d ",*p);
}
printf("\n");
}
}
int main(){
memset(fa,0,sizeof(fa));
scanf("%d",&n);
for(int i=0;i<=n;i++){
fa[i] = i;
cld[i].push_back(i);
}
for(int i=1;i<n;i++){
int a,b,c;
scanf("%d%d",&a,&b);
solve(a,b);
//print();
}
for(vector<int>::iterator p = cld[1].begin();p!=cld[1].end();p++){
printf("%d ",*(p));
}
printf("\n");
return 0;
}