https://codeforces.com/contest/1494/problem/D
因为上级严格比下级大,把a[i][j]从小到大排序,然后就能从下往上构造了,并查集模拟一下
注意排序的同时,还要把i,j排序,也就是一堆相同的值中,先把i的全部给构造完了,这样就不会出现冲突了
upd:有人问我把i,j排序是为啥,我还是举个栗子
比如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;
typedef long long ll;
const int maxl=5e5+10;
int n,m,k,cnt,tot,cas,ans;
int a[510][510],c[maxl],f[maxl],fa[maxl];
struct node
{
int val,i,j;
}b[510*510];
bool vis[maxl];
char s[maxl];
inline bool cmp(const node &a,const node &b)
{
if(a.val==b.val)
{
if(a.i==b.i)
return a.j<b.j;
return a.i<b.i;
}
return a.val<b.val;
}
inline void prework()
{
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)
b[++cnt]=node{a[i][j],i,j};
else if(i==j)
c[i]=a[i][j],f[i]=i;
}
sort(b+1,b+1+cnt,cmp);
}
inline int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
inline void mainwork()
{
tot=n;
for(int i=1;i<=cnt;i++)
{
int l=find(b[i].i),r=find(b[i].j);
if(l==r)
continue;
int top=max(c[l],c[r]);
if(top==b[i].val)
{
if(c[l]==b[i].val)
f[r]=l,fa[r]=l;
else
f[l]=r,fa[l]=r;
}
else if(top<b[i].val)
{
++tot;
f[tot]=tot;c[tot]=b[i].val;
f[l]=f[r]=tot;fa[l]=fa[r]=tot;
}
}
}
inline void print()
{
printf("%d\n",tot);
for(int i=1;i<=tot;i++)
printf("%d%c",c[i]," \n"[i==tot]);
int rt=0;
for(int i=1;i<=tot;i++)
if(find(i)==i)
rt=i;
printf("%d\n",rt);
for(int i=1;i<=tot;i++)
if(find(i)!=i)
printf("%d %d\n",i,fa[i]);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}