题目大意:
给你 n 个叶子节点,给你任意两个节点的 LCA 的权值,让你构建一棵树,要求父亲节点的权值一定严格大于儿子节点的权值。
输出:
第一行表示这棵树的总结点 k
第二行表示这棵树每一个节点的权值
第三行表示这棵树的根节点
接下来 k - 1 行,每一行表示条边,第一个是子节点,第二个是父节点
数据范围:
n<=500, 权值 <=5000
题解:
- 首先对于 (a[i][i]) 表示 (i) 这个位置的权值
- 因为这棵树从叶子节点往根节点走,权值一定是不断变大的,所以先处理小的,然后处理大的,对权值排个序。
- 在处理的过程中,要注意,如果权值相同,那么先处理节点在之前出现过的值,因为和 u 节点相连的所有值相同的节点,都会连在一个父亲节点。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 500;
const int maxm = 3e5+10;
int a[maxn][maxn],val[maxn];
struct node{
int x,y,v;
node(int x=0,int y=0,int v=0):x(x),y(y),v(v){}
}e[maxm];
bool cmp(node a,node b){
if(a.v==b.v) return a.x<b.x;
return a.v<b.v;
}
vector<int>G[maxm];
int f[maxm];
int findx(int u){
return f[u]==u?u:f[u] = findx(f[u]);
}
int main(){
int n,now = 0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
if(i==j) val[i] = a[i][j];
if(j>i) e[++now] = node(i,j,a[i][j]);
}
}
int cur = n;
sort(e+1,e+1+now,cmp);
for(int i=0;i<maxm;i++) f[i] = i;
int pre = 0;
for(int i=1;i<=now;i++){
int u = e[i].x,v = e[i].y,num = e[i].v;
u = findx(u),v = findx(v);
if(u==v) continue;
if(u==pre&&num==e[i-1].v) f[v] = cur,G[cur].push_back(v);
else{
++cur,pre = cur,f[u] = cur,f[v] = cur;
G[cur].push_back(u),G[cur].push_back(v),val[cur] = num;
}
}
printf("%d
",cur);
for(int i=1;i<=cur;i++){
printf("%d",val[i]);
if(i==cur) printf("
");
else printf(" ");
}
printf("%d
",findx(1));
for(int i=1;i<=cur;i++){
for(int j=0;j<G[i].size();j++){
printf("%d %d
",G[i][j],i);
}
}
}
/*
6
17 20 20 20 19 20
20 17 18 18 20 18
20 18 14 16 20 16
20 18 16 14 20 16
19 20 20 20 17 20
20 18 16 16 20 15
*/