Codeforces 35E(区间更新)

题意:要建n个高楼,给出了每个高楼的左右区间和高度,问最后所有的高楼的轮廓包括了哪些点。
题解:这题好坑,用了n种姿势了还是一直wa,后来才直到必须加输入输出文件那句话才能过。。。用线段树存维护区间内最大值也就是高度,左右区间到1e9所以要离散化。因为维护的是每一段的最大值而不是点,所以划分左右子区间那里要把mid到mid+1也归到右子区间里。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 100005;
int n, a[N << 1], h[N], l[N], r[N], hh;
int tree[N << 4], res[N << 3][2];
map<int, int> mp;

void pushdown(int k) {
    if (tree[k]) {
        tree[k * 2] = max(tree[k * 2], tree[k]);
        tree[k * 2 + 1] = max(tree[k * 2 + 1], tree[k]);
        tree[k] = 0;
    }
}

void modify(int k, int left, int right, int l1, int r1, int x) {
    if (l1 <= left && right <= r1) {
        tree[k] = max(tree[k], x);
        return;
    }
    pushdown(k);
    int mid = (left + right) / 2;
    if (l1 < mid)
        modify(k * 2, left, mid, l1, r1, x);
    if (r1 > mid)
        modify(k * 2 + 1, mid, right, l1, r1, x);
}

void query(int k, int left, int right, int l1, int r1) {
    if (left + 1 == right) {
        hh = tree[k];
        return;
    }
    pushdown(k);
    int mid = (left + right) / 2;
    if (l1 < mid)
        query(k * 2, left, mid, l1, r1);
    else
        query(k * 2 + 1, mid, right, l1, r1);
}

int main() {
    freopen("input.txt", "r", stdin);  
    freopen("output.txt", "w", stdout);
    scanf("%d", &n);
    memset(tree, 0, sizeof(tree));
    mp.clear();
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%d%d%d", &h[i], &l[i], &r[i]);
        a[cnt++] = l[i];
        a[cnt++] = r[i];
    }
    sort(a, a + cnt);
    cnt = unique(a, a + cnt) - a;
    for (int i = 0; i < cnt; i++)
        mp[a[i]] = i;

    for (int i = 1; i <= n; i++)
        modify(1, 0, cnt - 1, mp[l[i]], mp[r[i]], h[i]);
    int num = 0, curh = 0;
    for (int i = 0; i < cnt - 1; i++) {
        query(1, 0, cnt - 1, i, i + 1);
        if (hh != curh) {
            res[num][0] = a[i];
            res[num++][1] = curh;
            res[num][0] = a[i];
            res[num++][1] = hh;
            curh = hh;
        }
    }
    if (curh) {
        res[num][0] = a[cnt - 1];
        res[num++][1] = curh;
        res[num][0] = a[cnt - 1];
        res[num++][1] = 0;
    }
    printf("%d\n", num);
    for (int i = 0; i < num; i++)
        printf("%d %d\n", res[i][0], res[i][1]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值