ZOJ 3299 Fall the Brick(线段树区间更新)

本文探讨了一种解决板砖与木板高效匹配问题的算法,通过线段树进行区间更新,实现了复杂度优化。算法首先对边界进行离散化,按木板高度排序,对区间进行染色,再将所有砖块放入并更新区间,最终通过叶子节点查询得到答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

有n块板砖从天而降,底下有了m块木板来挡,每块板砖长度为1单位。
现在题目给出连续板砖的范围还有木板的范围与高度,问最后每块木板上有几块板砖。

解析:

这题想了挺久的最后终于搞定了。
线段树的区间更新问题。
由于liri比较大(0<=li<ri<=30000000),首先考虑到的是对左右边界进行离散化。然后先按照木板从低到高进行排序,然后对区间进行染色。
然后再把所有的砖块放上去,对区间进行更新,维护一个addv的懒惰标记,代表这个区间被覆盖了多少层。
最后进行到一次直到叶子节点的总查询得到最终答案。
总复杂度O((n+m+tot)log2n)

注意:

这题对内存的要求比较高,开小了会re,开大了会mle。

my code

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
typedef long long ll;

const int N = 100005;
struct Node {
    int ll, rr, lid, rid;
    int h, id;
} brick[N], board[N];

int n, m, tot;
int id[N*6];
ll length[N*6], ans[N];

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

void discrete() {
    sort(id, id+tot);
    tot = unique(id, id+tot) - id;
    for(int i = 1; i <= n; i++) {
        brick[i].lid = lower_bound(id, id+tot, brick[i].ll) - id;
        brick[i].rid = lower_bound(id, id+tot, brick[i].rr) - id - 1;
    }
    for(int i = 1; i <= m; i++) {
        board[i].lid = lower_bound(id, id+tot, board[i].ll) - id;
        board[i].rid = lower_bound(id, id+tot, board[i].rr) - id - 1;
    }
    for(int i = 0; i < tot-1; i++) {
        length[i] = id[i+1] - id[i];
    }
}

ll color[N*12], addv[N*12];
void build(int o, int L, int R) {
    color[o] = addv[o] = 0;
    if(L == R) return ;
    int M = (L + R)/2;
    build(lson);
    build(rson);
}

void pushDown(int o) {
    if(color[o]) {
        color[ls] = color[rs] = color[o];
        color[o] = 0;
    }
    if(addv[o]) {
        addv[ls] += addv[o]; addv[rs] += addv[o];
        addv[o] = 0;
    }
}

void setColor(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr) {
        color[o] = val;
        return ;
    }
    pushDown(o);
    int M = (L + R)/2;
    if(ql <= M) setColor(lson, ql, qr, val);
    if(qr > M) setColor(rson, ql, qr, val);
}

void modify(int o, int L, int R, int ql, int qr) {
    if(ql <= L && R <= qr) {
        addv[o]++;
        return ;
    }
    pushDown(o);
    int M = (L + R)/2;
    if(ql <= M) modify(lson, ql, qr);
    if(qr > M) modify(rson, ql, qr);
}

void query(int o, int L, int R) {
    if(L == R) {
        if(color[o])
            ans[color[o]] += addv[o]*length[L];
        return ;
    }
    pushDown(o);
    int M = (L + R)/2;
    query(lson);
    query(rson);
}

int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        tot = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &brick[i].ll, &brick[i].rr);
            id[tot++] = brick[i].ll;
            id[tot++] = brick[i].rr;
        }

        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &board[i].ll, &board[i].rr, &board[i].h);
            id[tot++] = board[i].ll;
            id[tot++] = board[i].rr;
            board[i].id = i;
        }

        discrete();
        int end = tot-2;
        build(1, 0, end);

        sort(board+1, board+m+1, cmp);
        for(int i = 1; i <= m; i++)
            setColor(1, 0, end, board[i].lid, board[i].rid, board[i].id);
        for(int i = 1; i <= n; i++)
            modify(1, 0, end, brick[i].lid, brick[i].rid);

        memset(ans, 0, sizeof(ans));
        query(1, 0, end);

        for(int i = 1; i <= m; i++)
            printf("%lld\n", ans[i]);
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值