D. Dogeforces 思维

D. Dogeforces 思维

题目大意:

给你 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
 */
原文地址:https://www.cnblogs.com/EchoZQN/p/14477028.html