Bzoj5100 [poi2018]plan metra

神仙构造

阅读全文大概需要 1分钟
本文总阅读量
Posted by yjjr's blog on April 7, 2018

标签:构造

题目

题目传送门

Description

有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度。

已知2到\(n-1\)每个点在树上与1和n的距离,请根据这些信息还原出这棵树。

Input

第一行包含一个正整数\(n(2\leq n\leq 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\leq d\leq 1000000\)。

Output

若无解,输出NIE。

否则第一行输出TAK,接下来n-1行每行三个正整数

\(u,v,c(1\leq u,v\leq n,1\leq c\leq 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号点不存在直接连边,那么我们又要分外两部分考虑

  1. 该点位于1号点和n号点之间的路径上,此时需要满足这条链上任意两个点位置不同,我们可以求出1号点和n号点之间的距离\(D=\min(dis(1,i)+dis(i,n))\)
  2. 对于其他点,一定是先连接到这条路径上的某一个点,然后通过这个点再连向两端的1/n号点,此时需要满足条件\(dis(1,x)+dis(x,n)-D\)为偶数且\(abs(dis(1,x)-dis(x,n))\leq d\),且存在这条路径上的某个点到1/n号点的距离为\(dis(1/n,x)-\frac {dis(1/n,x)+dis(n/1,x)-D} {2}\)

满足这些条件的时候,可以构造出解:这条路径上的相邻两点连边,其余的点向路径上的点连边,查找对应点时可以用二分查找

如果上述的两种大情况都不满足,那么就无解

时间复杂度\(O(n\log n)\)

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define dep(i,a,b) for(register int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
	ll f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
//**********head by yjjr**********
const int maxn=5e5+6;
struct node{int d,p;}v[maxn];
int n,t,len=1e9,val,a[maxn],b[maxn],l[maxn],tot,x[maxn],y[maxn],z[maxn],cnt;
inline bool operator < (const node &a,const node &b){return a.d<b.d;}
int main(){
	int i;
    n=read();
    if(n==2){puts("TAK\n1 2 1");return 0;}
    rep(i,2,n-1)a[i]=read();
    rep(i,2,n-1)b[i]=read(),l[i]=a[i]+b[i],len=min(len,l[i]);
    if(a[2]!=b[2]){
        val=max(a[2]-b[2],b[2]-a[2]);
        for(i=3;i<n;i++)if(a[i]-b[i]!=val&&b[i]-a[i]!=val)break;
        if(i==n){
            printf("TAK\n1 %d %d\n",n,val);
            rep(i,2,n-1)if(a[i]<b[i])printf("1 %d %d\n",i,a[i]);else printf("%d %d %d\n",n,i,b[i]);
            return 0;
        }
    }
	rep(i,2,n-1)if(l[i]==len)v[++tot]=(node){a[i],i};
	v[++tot]=(node){len,n};v[++tot]=(node){0,1};
	sort(v+1,v+1+tot);
	rep(i,1,tot-1){
		if(v[i].d==v[i+1].d){puts("NIE");return 0;}
		x[++cnt]=v[i].p,y[cnt]=v[i+1].p,z[cnt]=v[i+1].d-v[i].d;
	}
	rep(i,2,n-1)
		if(l[i]!=len){
			if((l[i]-len)&1||(t=lower_bound(v+1,v+1+tot,(node){a[i]-((l[i]-len)>>1),0})-v)>tot||
			v[t].d!=a[i]-((l[i]-len)>>1)){puts("NIE");return 0;}
			x[++cnt]=v[t].p,y[cnt]=i,z[cnt]=(l[i]-len)>>1;
		}
	puts("TAK");
	rep(i,1,cnt)printf("%d %d %d\n",x[i],y[i],z[i]);
	return 0;
}
本文可以转载,但必须附上原文链接,否则你会终生找不到妹子!!!欢迎关注我的CSDN: ahyjjr