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
*/


posted @ 2021-03-09 21:22  dinlon  阅读(80)  评论(0)    收藏  举报