AcWing 248. 窗内的星星

'两个囚犯从监狱的窗子里向外看,一个凝视着泥土,一个仰望着星空'

#include <bits/stdc++.h>
// #define LOCAL
#define INF 0xf3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
#define debug(a) cout << #a << "=" << a << endl;
using namespace std;
const int N = 1e4 + 10;
int n, W, H;
struct line{
    int x, y1, y2;
    int c;
    bool friend operator <(line A, line B){
        return (A.x != B.x) ? (A.x < B.x) : (A.c > B.c);
    }
}a[N << 1];
struct tr{
    int l, r;
    int add;
    int mx;
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define add(x) tree[x].add
    #define mx(x) tree[x].mx
}tree[N << 3];

int raw[N << 1], val[N << 1][2];
int tot, ans;
void build(int p, int l, int r){
    l(p) = l, r(p) = r;
    add(p) = mx(p) = 0;
    if (l == r)
        return;
    int mid = l + r >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
}
void push_up(int p){
    mx(p) = max(mx(p << 1), mx(p << 1 | 1));
}
void push_down(int p){
    if (!add(p))
        return;
    mx(p << 1) += add(p);
    mx(p << 1 | 1) += add(p);
    add(p << 1) += add(p);
    add(p << 1 | 1) += add(p);
    add(p) = 0;
}
void change(int p, int l, int r, int d){
    if (l <= l(p) && r >= r(p)){
        mx(p) += d;
        add(p) += d;
        return;
    }
    push_down(p);
    int mid = l(p) + r(p) >> 1;
    if (l <= mid)
        change(p << 1, l, r, d);
    if (r > mid)
        change(p << 1 | 1, l, r, d);
    push_up(p);
}
int ask(int p, int l, int r){
    if (l <= l(p) && r >= r(p))
        return mx(p);
    push_down(p);
    int mid = l(p) + r(p) >> 1;
    int v = 0;
    if (l <= mid)
        v = max(v, ask(p << 1, l, r));
    if (r > mid)
        v = max(v, ask(p << 1 | 1, l, r));
    return v;
}
signed main(){
#ifdef LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
#endif
    IOS;
    while (cin >> n >> W >> H){
        tot = ans = 0;
        for (int i = 1, x, y, c; i <= n; ++i){
            cin >> x >> y >> c;
            a[i * 2 - 1] = {x, y, y + H - 1, c};
            a[i * 2] = {x + W - 1, y, y + H - 1, -c};
            raw[++tot] = y;
            raw[++tot] = y + H - 1;
        }
        sort(a + 1, a + 1 + n * 2);
        sort(raw + 1, raw + 1 + tot);
        tot = unique(raw + 1, raw + 1 + tot) - (raw + 1);
        for (int i = 1; i <= n * 2; ++i){
            val[i][0] = lower_bound(raw + 1, raw + 1 + tot, a[i].y1) - raw;
            val[i][1] = lower_bound(raw + 1, raw + 1 + tot, a[i].y2) - raw;
        }
        build(1, 1, tot);
        for (int i = 1; i <= n * 2; ++i){
            change(1, val[i][0], val[i][1], a[i].c);
            ans = max(ans, ask(1, 1, tot));
        }
        cout << ans << '\n';
    }
}

这题跟亚特兰蒂斯的解法相似,都是用扫描线,但是这题需要下传懒惰标记,因为面积需要叠加计算,也就是说每个子矩阵对面积都是有贡献的.

另外值得一提的是这题的思路.

1.这道题正面求比较难求,转化成用每个星星表示一个区域求覆盖面积

类似比较精妙的题目还有:雷达设备

2.通过等价转化的方法避免了边界问题的处理,因为矩形边上的星星不算,所以把矩形的四个左边都往中心缩小0.5个单位,就等价于(x, y, x + W - 1, y + H - 1).

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值