题解:洛谷 P1904 天际线

【题目来源】

洛谷:P1904 天际线 - 洛谷

【题目描述】

Latium 省的 Genoa 是亚平宁半岛西海岸北端的一片土地,自然资源丰富,却无人居住。你受到罗马执政官 Caesar 的委任,前往 Genoa 建立新的城市。Caesar 对这次任务的要求是在 Genoa 这片土地上建立起一座繁荣的城市,他将以此作为衡量你的表现的标准。

正在你大刀阔斧地进行城市建设的时候,Caesar 突然写信给你,说他要检查 Genoa 的建设情况。Caesar 希望知道你的城市是什么样子,但是他又非常的忙,所以他只要你描述一下城市的轮廓就可以了,他将依照城市的轮廓决定你的薪水。

怎样描述一个城市的轮廓呢?我们知道 Genoa 所有的建筑共享一个地面,你可以认为它是水平的。所有的建筑用一个三元组 \((L_i,H_i,R_i)\),其中 \(L_i\)\(R_i\) 分别是建筑的左坐标和右坐标,\(H_i\) 就是建筑的高度。在下方所示的图表中左边建筑物描述如下 \((1,11,5)\)\((2,6,7)\)\((3,13,9)\)\((12,7,16)\)\((14,3,25)\)\((19,18,22)\)\((23,13,29)\)\((24,4,28)\),右边用轮廓线的顺序 \((1,11,3,13,9,0,12,7,16,3,19,18,22,3,23,13,29,0)\) 表示:

image

【输入】

在输入数据中,你将得到一系列表示建筑的三元组。在输入数据中所有建筑的坐标中的数值都是小于 \(10000\) 的正整数,且至少有 \(1\) 幢建筑,最多有 \(5000\) 幢建筑。在输入输入中每幢建筑的三元组各占一行。三元组中的所有整数应由一个或多个空格分开。

【输出】

在输出数据中,你被要求给出城市的轮廓线。你可以这样来描述:对于所有轮廓线上的折点,按顺序排好,第奇数个点输出 \(x\) 坐标,第偶数个点输出 \(y\) 坐标,两个数之间用空格分开。

【输入样例】

1 11 5
2 6 7
3 13 9
12 7 16
14 3 25
19 18 22
23 13 29
24 4 28

【输出样例】

1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0

【解题思路】

image

【算法标签】

《洛谷 P1904 天际线》 #模拟# #线段树# #离散化#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 定义全局变量
int a[5005], b[5005], h[5005];  // 存储每个建筑的起点、终点和高度
int cnt;                        // 建筑计数器
int c[100005], k;               // 离散化坐标数组及其计数器
int f[10005];                   // 记录每个离散化区间的高度
int ans[15005];                 // 存储最终的天际线坐标

int main()
{
    // 读取输入数据直到文件结束
    while (cin >> a[cnt] >> h[cnt] >> b[cnt]) 
    {
        // 将起点和终点坐标存入离散化数组
        c[k++] = a[cnt];
        c[k++] = b[cnt];
        cnt++;
    }

    // 对坐标进行排序和去重(离散化处理)
    sort(c, c + k);
    int size = unique(c, c + k) - c;  // 获取唯一坐标的数量

    // 离散化处理:将原始坐标映射到排序后的索引
    for (int i = 0; i < cnt; i++) 
    {
        a[i] = lower_bound(c, c + size, a[i]) - c;
        b[i] = lower_bound(c, c + size, b[i]) - c;
        
        // 更新每个离散化区间的高度
        for (int j = a[i]; j < b[i]; j++) 
        {
            if (f[j] < h[i]) 
            {
                f[j] = h[i];
            }
        }
    }

    // 构建天际线坐标序列
    ans[0] = c[0];  // 第一个坐标
    int x = 1;      // 结果数组的索引

    // 遍历离散化后的区间,检测高度变化点
    for (int i = 1; i < size; i++) 
    {
        if (f[i] != f[i - 1]) 
        {
            ans[x++] = f[i - 1];  // 记录前一个高度
            ans[x++] = c[i];      // 记录当前坐标
        }
    }

    // 输出结果
    for (int i = 0; i < x; i++) 
    {
        cout << ans[i] << " ";
    }
    cout << "0" << endl;  // 天际线结束标志

    return 0;
}

【运行结果】

1 11 5
2 6 7
3 13 9
12 7 16
14 3 25
19 18 22
23 13 29
24 4 28
^Z
1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0
posted @ 2026-02-18 21:18  团爸讲算法  阅读(2)  评论(0)    收藏  举报