zoukankan      html  css  js  c++  java
  • 【BZOJ5100】[POI2018]Plan metra 构造

    【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
    1 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
    ",pa[i],pb[i],pc[i]);
    	return 0;
    }//6 2 5 4 8 4 1 6 4
  • 相关阅读:
    浅谈最长上升子序列(LIS)
    浅谈树链剖分
    数字计数
    windy数
    骑士(树形dp)
    旅游规划
    皇宫看守
    k8s安装报错
    linux文件夹存储潜规则
    搭建覆盖率测试环境
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7954085.html
Copyright © 2011-2022 走看看