D. Dogeforces 题解(并查集+构造)

题目链接

题目大意

要你构造一棵树

给你所有树的叶子,数目为n

并且告诉你所有叶子的lca所代表的权值

且祖宗节点的权值必定比儿子节点的权值大

题目思路

参考代码:https://blog.csdn.net/liufengwei1/article/details/114298063

就是并查集模拟

因为祖宗比儿子大,把a\([i][j]\)从小到大排序,然后从下往上构造了,要利用并查集模拟

而且排序的时候还要按照i排序

原因

比如1 2 3 4都是父亲是5,但是你在排序的时候搞出了1 2父亲是5,然后处理3 4,发现他们的父节点都是他们自己,所以搞出个新节点父亲6,最后发现1,3的父亲还是权值和5,6一样,就会出问题,相当于多创建了一个点,但如果一开始排序就先 1 2 ,1 3,1 4,就会只有一个父亲5

代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<double,int> pdi;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=500+5,mod=1e7;
int n,m;
int fa[maxn*maxn];
int a[maxn][maxn];
int v[maxn*maxn];
int c[maxn*maxn];
struct edge{
    int l,r,val;
}e[maxn*maxn];
pair<int,int> ans[maxn*maxn];
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool cmp(edge a,edge b){
    if(a.val!=b.val){
        return a.val<b .val;
    }else {
        return a.l<b.l;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
            e[i+(j-1)*n]={i,j,a[i][j]};
        }
    }
    m=n;
    for(int i=1;i<=n;i++){
        fa[i]=i;
        c[i]=a[i][i];
    }
    sort(e+1,e+1+n*n,cmp);
    int cnt=0;
    for(int i=1;i<=n*n;i++){
        int x=find(e[i].l),y=find(e[i].r);
        if(x==y) continue;
        if(c[x]==e[i].val){
            fa[y]=x;
            ans[++cnt]={y,x};
        }else if(c[y]==e[i].val){
            fa[x]=y;
            ans[++cnt]={x,y};
        }else{
            fa[x]=fa[y]=++m;
            fa[m]=m;
            c[m]=e[i].val;
            ans[++cnt]={x,m};
            ans[++cnt]={y,m};
        }
    }
    printf("%d\n",m);
    for(int i=1;i<=m;i++){
        printf("%d ",c[i]);
    }
    printf("\n%d\n",find(1));
    for(int i=1;i<=cnt;i++){
        printf("%d %d\n",ans[i].fi,ans[i].se);
    }
    return 0;
}

不摆烂了,写题
原文地址:https://www.cnblogs.com/hunxuewangzi/p/14475065.html