【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(n\log 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\n1 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\n1 %d %d\n" , n , val);
            for(i = 2 ; i < n ; i ++ )
            {
                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;
        }
    }
    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\n" , x[i] , y[i] , z[i]);
    return 0;
}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/8011391.html

### 光流法C++源代码解析与应用 #### 光流法原理 光流法是一种在计算机视觉领域中用于追踪视频序列中运动物体的方法。它基于亮度不变性假设,即场景中的在时上保持相同的灰度值,从而通过分析连续帧之的像素变化来估计运动方向速度。在数学上,光流场可以表示为像素位置的一阶导数,即Ex、Ey(空梯度)Et(时梯度),它们共同构成光流方程的基础。 #### C++实现细节 在给定的C++源代码片段中,`calculate`函数负责计算光流场。该函数接收一个图像缓冲区`buf`作为输入,并初始化了几个关键变量:`Ex`、`Ey``Et`分别代表沿x轴、y轴轴的像素强度变化;`gray1``gray2`用于存储当前帧前一帧的平均灰度值;`u`则表示计算出的光流矢量大小。 #### 图像处理流程 1. **初始化预处理**:`memset`函数被用来清零`opticalflow`数组,它将保存计算出的光流数据。同时,`output`数组被填充为白色,这通常用于可视化结果。 2. **灰度计算**:对每一像素进行处理,计算其灰度值。这里采用的是RGB通道平均值的计算方法,将每个像素的R、G、B值相加后除以3,得到一个近似灰度值。此步骤确保了计算过程的鲁棒性效率。 3. **光流向量计算**:通过比较当前帧前一帧的灰度值,计算出每个像素的Ex、EyEt值。这里值得注意的是,光流向量的大小`u`是通过`Et`除以`sqrt(Ex^2 + Ey^2)`得到的,再乘以10进行量化处理,以减少计算复杂度。 4. **结果存储与阈值处理**:计算出的光流值被存储在`opticalflow`数组中。如果`u`的绝对值超过10,则认为该存在显著运动,因此在`output`数组中将对应位置标记为黑色,形成运动区域的可视化效果。 5. **状态更新**:通过`memcpy`函数将当前帧复制到`prevframe`中,为下一次迭代做准备。 #### 扩展应用:Lukas-Kanade算法 除了上述基础的光流计算外,代码还提到了Lukas-Kanade算法的应用。这是一种更高级的光流计算方法,能够提供更精确的运动估计。在`ImgOpticalFlow`函数中,通过调用`cvCalcOpticalFlowLK`函数实现了这一算法,该函数接受前一帧当前帧的灰度图,以及窗口大小等参数,返回像素级别的光流场信息。 在实际应用中,光流法常用于目标跟踪、运动检测、视频压缩等领域。通过深入理解优化光流算法,可以进一步提升视频分析的准确性实时性能。 光流法及其C++实现是计算机视觉领域的一个重要组成部分,通过对连续帧像素变化的精细分析,能够有效捕捉理解动态场景中的运动信息
微信小程序作为腾讯推出的一种轻型应用形式,因其便捷性与高效性,已广泛应用于日常生活中。以下为该平台的主要特性及配套资源说明: 特性方面: 操作便捷,即开即用:用户通过微信内搜索或扫描二维码即可直接使用,无需额外下载安装,减少了对手机存储空的占用,也简化了使用流程。 多端兼容,统一开发:该平台支持在多种操作系统与设备上运行,开发者无需针对不同平台进行重复适配,可在一个统一的环境中完成开发工作。 功能丰富,接口完善:平台提供了多样化的API接口,便于开发者实现如支付功能、用户身份验证及消息通知等多样化需求。 社交整合,传播高效:小程序深度嵌入微信生态,能有效利用社交关系链,促进用户之的互动与传播。 开发成本低,周期短:相比传统应用程序,小程序的开发投入更少,开发周期更短,有助于企业快速实现产品上线。 资源内容: “微信小程序-项目源码-原生开发框架-含效果截图示例”这一资料包,提供了完整的项目源码,并基于原生开发方式构建,确保了代码的稳定性与可维护性。内容涵盖项目结构、页面设计、功能模块等关键部分,配有详细说明与注释,便于使用者迅速理解并掌握开发方法。此外,还附有多个实际运行效果的截图,帮助用户直观了解功能实现情况,评估其在实际应用中的表现与价值。该资源适用于前端开发人员、技术爱好者及希望拓展业务的机构,具有较高的参考与使用价值。欢迎查阅,助力小程序开发实践。资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值