Dogeforces
\(Dogeforces\)
首先有一个n\(n\le500\)个叶子的树,除了叶子每个点至少有两个儿子,每个点有权值,每个点的权值都严格小于它的父亲,给出一个矩阵,表示所有叶子两两的\(lca\)的权值。现在要求构造出这个树,输出每条边连接的点。
首先我们采用增量构造法的思路,每次加入一个叶子并连边,使得它满足已经加入的点的限制,那么它和已经其他叶子的lca一定在它到根节点的链上,那么我们可以求出当前点到已经加入的节点中深度最深的那一个,从这个节点向上的链一定已经加入了,下面的链按照权值大小加入即可。那么我们需要存储一下对应位置的节点编号。然后对应维护即可。
#include<bits/stdc++.h>
#define LL long long
#define V inline void
#define I inline int
#define FOR(i,a,b) for(register int i=a,end##i=b;i<=end##i;++i)
#define REP(i,a,b) for(register int i=a,end##i=b;i>=end##i;--i)
#define go(i,x) for(int i=hed[x];i;i=e[i].pre)
using namespace std;
inline int read()
{
char x='\0';
int fh=1,sum=0;
for(x=getchar();x<'0'||x>'9';x=getchar())if(x=='-')fh=-1;
for(;x>='0'&&x<='9';x=getchar())sum=sum*10+x-'0';
return fh*sum;
}
const int N=509;
const int INF=0x3f3f3f3f;
int n,a[N][N],id[N][N],vid[N][5009];
int b[N],bcnt;
int indx;
struct lian{
int to,pre;
}e[N*N*5];
int hed[N*N],lcnt=1;
V jlian(int x,int y)
{
e[++lcnt]={y,hed[x]};
hed[x]=lcnt;
}
int val[N*N];
int f[N*N];
V dfs(int x,int fa)
{
f[x]=fa;
go(i,x)
{
int to=e[i].to;
if(to==fa)continue;
dfs(to,x);
}
}
int main()
{
n=read();
indx=n;
FOR(i,1,n)FOR(j,1,n)a[i][j]=read();
bcnt=0;
FOR(i,1,n)b[++bcnt]=a[1][i];
sort(b+1,b+bcnt+1);
bcnt=unique(b+1,b+bcnt+1)-b-1;
vid[1][b[1]]=1;
FOR(i,2,bcnt)
{
vid[1][b[i]]=++indx;
val[indx]=b[i];
jlian(vid[1][b[i-1]],vid[1][b[i]]);
jlian(vid[1][b[i]],vid[1][b[i-1]]);
}
FOR(i,1,n)id[1][i]=vid[1][a[1][i]];
FOR(i,2,n)
{
int mn=INF,p=0;
FOR(j,1,i-1)if(a[j][i]<mn)mn=a[j][i],p=j;
// cout<<i<<' '<<mn<<' '<<p<<endl;//
bcnt=0;
FOR(j,1,n)b[++bcnt]=a[i][j];
sort(b+1,b+bcnt+1);
bcnt=unique(b+1,b+bcnt+1)-b-1;
vid[i][b[1]]=i;
FOR(j,2,bcnt)
{
if(b[j]==mn)
{
// cout<<p<<' '<<id[p][i]<<' '<<vid[i][b[j-1]]<<endl;//
jlian(id[p][i],vid[i][b[j-1]]);
jlian(vid[i][b[j-1]],id[p][i]);
break;
}
vid[i][b[j]]=++indx;
val[indx]=b[j];
jlian(vid[i][b[j-1]],vid[i][b[j]]);
jlian(vid[i][b[j]],vid[i][b[j-1]]);
}
FOR(j,1,n)
{
int now=a[i][j];
if(now<mn)id[i][j]=vid[i][now];
else id[i][j]=vid[i][now]=vid[p][now];
// cout<<"id "<<i<<' '<<j<<' '<<id[i][j]<<endl;//
// cout<<p<<' '<<b[j]<<" "<<vid[p][b[j]]<<endl;
}
}
int mx=0,x=0;
FOR(i,1,n)FOR(j,1,n)
{
if(a[i][j]>mx)
{
mx=a[i][j];
x=id[i][j];
}
}
dfs(x,0);
printf("%d\n",indx);
FOR(i,1,n)val[i]=a[i][i];
FOR(i,1,indx)printf("%d%c",val[i],(i==indx)?'\n':' ');
printf("%d\n",x);
FOR(i,1,indx)if(i!=x)printf("%d %d\n",i,f[i]);
return 0;
}
/*
5
1 27 28 28 12
27 2 28 28 27
28 28 3 26 28
28 28 26 4 28
12 27 28 28 5
*/