1. 程式人生 > >【BZOJ5100】[POI2018]Plan metra 構造

【BZOJ5100】[POI2018]Plan metra 構造

reg 接下來 names plan out sta return content stdin

【BZOJ5100】[POI2018]Plan metra

Description

有一棵n個點的無根樹,每條邊有一個正整數權值,表示長度,定義兩點距離為在樹上的最短路徑的長度。 已知2到n-1每個點在樹上與1和n的距離,請根據這些信息還原出這棵樹。

Input

第一行包含一個正整數n(2<=n<=500000),表示點數。 第二行包含n-2個正整數d(1,2),d(1,3),...,d(1,n-1),分別表示每個點到1的距離。 第三行包含n-2個正整數d(n,2),d(n,3),...,d(n,n-1),分別表示每個點到n的距離。 輸入數據保證1<=d<=1000000。

Output

若無解,輸出NIE。 否則第一行輸出TAK,接下來n-1行每行三個正整數u,v,c(1<=u,v<=n,1<=c<=1000000) 表示存在一條長度為c的連接u和v兩點的樹邊。 若有多組解,輸出任意一組。

Sample Input

7
6 6 2 2 1
5 3 5 1 4

Sample Output

TAK
1 5 2
5 7 1
5 2 4
7 3 3
1 4 2
1 6 1

題解:如果我們已經確定了點1到點n的距離,那麽我們就可以將1到n這條路拿出來,然後其他點都想掛鏈一樣掛到這條路徑上即可。即:

如果1到n的長度是m,我們將所有d1-dn相同的點放到一起,那麽對於每組d1-dn相同的點,要麽|d1-dn|=m,要麽d1+dn的最小值=m。所以用數組記錄一下即可。

輸出方案的時候將所有d1+dn=m的點排個序即可。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=500010;
const int M=1000010;
int n,m,tot,cnt;
int d1[N],d2[N],s1[M<<1],s2[M<<1],p[M],mn[M<<1],pa[N],pb[N],pc[N];
inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=nc();
	while(!isdigit(gc))	{if(gc==‘-‘)	f=-f;	gc=nc();}
	while(isdigit(gc))	ret=ret*10+(gc^‘0‘),gc=nc();
	return ret*f;
}
inline int abs(int x) {return x>0?x:-x;}
inline bool check(int x)
{
	if(((x>=M||x<=-M)?0:(s1[M+x]+s1[M-x]))+s2[x]==n-2)
	{
		m=x;
		return 1;
	}
	return 0;
}
inline void add(int a,int b,int c)
{
	pa[++cnt]=a,pb[cnt]=b,pc[cnt]=c;
}
int main()
{
	n=rd();
	if(n==2)
	{
		printf("TAK\n1 2 1");
		return 0;
	}
	register int i,last;
	for(i=2;i<n;i++)	d1[i]=rd();
	for(i=2;i<n;i++)
	{
		d2[i]=rd();
		int &t=mn[d2[i]-d1[i]+M];
		if(!t||d1[t]+d2[t]>d1[i]+d2[i])	t=i;
		s1[d2[i]-d1[i]+M]++;
	}
	for(i=2;i<n;i++)	if(i==mn[d2[i]-d1[i]+M])	s2[d1[i]+d2[i]]+=s1[d2[i]-d1[i]+M];
	for(i=2;i<n;i++)	if(check(abs(d2[i]-d1[i]))||check(d1[i]+d2[i]))	break;
	if(!m)
	{
		puts("NIE");
		return 0;
	}
	for(i=2;i<n;i++)
	{
		if(d2[i]-d1[i]==m)	add(i,1,d1[i]);
		else	if(d1[i]-d2[i]==m)	add(i,n,d2[i]);
		else	if(i==mn[d2[i]-d1[i]+M])	p[d1[i]]=i;
		else
		{
			int t=mn[d2[i]-d1[i]+M];
			add(i,t,(d1[i]+d2[i]-d1[t]-d2[t])>>1);
		}
	}
	p[m]=n,d1[n]=m;
	for(last=i=1;i<=m;i++)	if(p[i])	add(last,p[i],d1[p[i]]-d1[last]),last=p[i];
	for(i=1;i<n;i++)	if(pc[i]<=0)
	{
		puts("NIE");
		return 0;
	}
	puts("TAK");
	for(i=1;i<n;i++)	printf("%d %d %d\n",pa[i],pb[i],pc[i]);
	return 0;
}//6 2 5 4 8 4 1 6 4

【BZOJ5100】[POI2018]Plan metra 構造