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

    题目描述

    有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度。
    已知2到n-1每个点在树上与1和n的距离,请根据这些信息还原出这棵树。

    输入

    第一行包含一个正整数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。

    输出

    若无解,输出NIE。
    否则第一行输出TAK,接下来n-1行每行三个正整数u,v,c(1<=u,v<=n,1<=c<=1000000)
    表示存在一条长度为c的连接u和v两点的树边。
    若有多组解,输出任意一组。

    样例输入

    7
    6 6 2 2 1
    5 3 5 1 4

    样例输出

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


    题解

    构造

    考虑两种情况:

    (1) $1$ 号点与 $n$ 号点直接相连

        此时需要满足:对于所有的 $i$ ,$|d(1,i)-d(n,i)|$ 均相等。

        满足此条件时容易构造出解: $1$ 号点与 $n$ 号点的边长度为 $|d(1,i)-d(n,i)|$ ;对于第 $i$ 个点,如果 $d(1,i)<d(n,i)$ 则与 $1$ 相连,长度为 $d(1,i)$ ;否则与 $n$ 相连,长度为 $d(n,i)$ 。

    (2) $1$ 号点与 $n$ 号点不直接相连

        此时 $1$ 号点与 $n$ 号点的距离为 $min{dis(1,i)+dis(n,i)}$ 。

        设这个距离为 $d$ ,那么对于所有的 $dis(1,i)+dis(n,i)=d$ 的点 $i$(包括 $1$ 号点和 $n$ 号点),将其按照 $dis(1,i)$ 从小到大排序,则它们形成了一条从 $1$ 到 $n$ 的链。此时需要满足:这条链上的任意两个点的位置(即 $dis(1,i)$ )均不同。

        然后考虑其它点:对于点 $x$ ,它到 $1$ 号点的方式一定是:先到达链上的某个点,然后再沿着链到 $1$ 。到 $n$ 同理。于是可以算出其到链上某个点的距离 $frac {dis(1,x)+dis(n,x)-d}2$ ,进而得到 $1$ 到这个链上点的距离。此时需要满足: $dis(1,x)+dis(n,x)-d$ 为偶数,且 $|dis(1,x)-dis(n,x)|le d$ ,且存在某个链上的点与 $1$ 的距离为 $dis(1,x)-frac {dis(1,x)+dis(n,x)-d}2$ 。

        满足这些条件时容易构造出解: $1$ 号点与 $n$ 号点的链之间的相邻两点 $a$ 和 $b$($a$ 比 $b$ 更靠近 $1$)连边,长度为 $dis(1,b)-dis(1,a)$ ,其余点向着链上对应的点连边,长度为 $frac{dis(1,x)+dis(n,x)-d}2$ 。

       查找对应点时可以使用二分查找解决。

    这两种情况均不满足时无解。

    时间复杂度 $O(nlog n)$

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define N 500010
    using namespace std;
    struct data
    {
        int d , p;
        data() {}
        data(int D , int P) {d = D , p = P;}
        bool operator<(const data &a)const {return d < a.d;}
    }v[N];
    int a[N] , b[N] , l[N] , tot , x[N] , y[N] , z[N] , cnt;
    int main()
    {
        int n , i , t , len = 1 << 30 , val;
        scanf("%d" , &n);
        if(n == 2)
        {
            puts("TAK
    1 2 1");
            return 0;
        }
        for(i = 2 ; i < n ; i ++ ) scanf("%d" , &a[i]);
        for(i = 2 ; i < n ; i ++ ) scanf("%d" , &b[i]) , 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
    1 %d %d
    " , n , val);
                for(i = 2 ; i < n ; i ++ )
                {
                    if(a[i] < b[i]) printf("1 %d %d
    " , i , a[i]);
                    else printf("%d %d %d
    " , n , i , b[i]);
                }
                return 0;
            }
        }
        v[++tot] = data(0 , 1);
        for(i = 2 ; i < n ; i ++ )
            if(l[i] == len)
                v[++tot] = data(a[i] , i);
        v[++tot] = data(len , n);
        sort(v + 1 , v + tot + 1);
        for(i = 1 ; i < tot ; i ++ )
        {
            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;
        }
        for(i = 2 ; i < n ; i ++ )
        {
            if(l[i] != len)
            {
                if((l[i] - len) & 1 || 
                   (t = lower_bound(v + 1 , v + tot + 1 , data(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");
        for(i = 1 ; i <= cnt ; i ++ ) printf("%d %d %d
    " , x[i] , y[i] , z[i]);
        return 0;
    }
    

     

  • 相关阅读:
    Eclipse 远程调试
    大数据处理方法bloom filter
    sicily 1259 Sum of Consecutive Primes
    sicily 1240. Faulty Odometer
    sicily 1152 简单马周游 深度优先搜索及回溯算法
    sicily 1050 深度优先搜索解题
    sicily 1024 邻接矩阵与深度优先搜索解题
    sicily 1156 二叉树的遍历 前序遍历,递归,集合操作
    sicily 1443 队列基本操作
    sicily 1006 team rankings 枚举解题
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8011391.html
Copyright © 2011-2022 走看看