[USACO07OPEN]城市的地平线City Horizon——优先队列

[USACO07OPEN]城市的地平线City Horizon——优先队列


题目来源

洛谷P2061


题目描述

Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouettes formed by the rectangular buildings.

The entire horizon is represented by a number line with N (1 ≤ N ≤ 40,000) buildings. Building i’s silhouette has a base that spans locations Ai through Bi along the horizon (1 ≤ Ai < Bi ≤ 1,000,000,000) and has height Hi (1 ≤ Hi ≤ 1,000,000,000). Determine the area, in square units, of the aggregate silhouette formed by all N buildings.

约翰带着奶牛去都市观光。在落日的余晖里,他们看到了一幢接一幢的摩天高楼的轮廓在地平线 上形成美丽的图案。以地平线为 X 轴,每幢高楼的轮廓是一个位于地平线上的矩形,彼此间可能有 重叠的部分。奶牛一共看到了 N 幢高楼,第 i 幢楼的高度是 Hi,两条边界轮廓在地平线上的坐标是 Ai 到 Bi。请帮助奶牛们计算一下,所有摩天高楼的轮廓覆盖的总面积是多少。

输入输出格式

输入格式:
第一行一个整数N,然后有N行,每行三个正整数ai、bi、Hi。

输出格式:
一个数,数列中所有元素的和。

输入输出样例

输入样例#1:
4
2 5 1
9 10 4
6 8 2
4 6 3
输出样例#1:
16

说明

N<=40000 , a、b、k<=10^9 。

解题报告

首先我们思考一个特殊情况:
如果在一段区间之内,建筑的最高点是保持不变的那么在这段区间内的面积我们可以通过乘法简单的算出来

由于楼房的个数有很多,所以整个区间被分为了很多个这样的特殊情况。所以我们只需要将分割区域的关键点按照找出来即可。显而易见的是这些关键点一定位于建筑在坐标轴上的起点与终点。

得到了关键点的位置,我们只需要通过一个优先队列维护两个关键点之间最高的建筑物,并有这个最高的建筑物更新答案即可


源代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>

using namespace std;

long long ans;

int n;

struct Node {
    int begin;
    int end;
    int value;

    bool operator < (Node a) const {
        return this -> value < a.value;
    }
} nodes[40005];

int pos[80005];

priority_queue <Node> que;

bool cmp(Node a, Node b) {
    return a.begin < b.begin;
}

bool _cmp(int a, int b) {
    return a < b;
}

int main() {
    freopen("in.txt", "r", stdin);

    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        scanf("%d%d%d", &nodes[i].begin, &nodes[i].end, &nodes[i].value);
        pos[i * 2] = nodes[i].end;
        pos[i * 2 - 1] = nodes[i].begin;
    }

    sort(pos + 1, pos + 1 + n * 2, _cmp);//按照从大到小的顺序排序关键点
    sort(nodes + 1, nodes + 1 + n, cmp);//按照左端点的顺序排序建筑物

    int put = 0;//已经放置的建筑物的个数
    for (int i = 1; i < n * 2; i++) {
        while (que.size() && que.top().end <= pos[i])//判断当前优先队列中最高的建筑物是否在范围之内
            que.pop();//若不在则出队
        while (pos[i] <= nodes[put + 1].begin && nodes[put + 1].begin < pos[i + 1])//将新出现在范围之内的建筑物入队
            que.push(nodes[++put]);

        if (que.size())//更新答案
            ans += (long long)(pos[i + 1] - pos[i]) * que.top().value;
    }

    printf("%lld", ans);

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值