动态开点线段树+lz更新

[题目链接] (https://codeforc.es/contest/500/problem/E)
题解:维护每个木棒能够覆盖的区间。
注意:因为要考虑一种情况就是前面的木棒如果将后面的位置都覆盖,那么结果就不正确了,所以要从后往前一边更新一边求答案。还有就是为什么更新时右端点要减一,举个例子,如果一根木棒在位置7,高度为1,一根木棒在位置9,高度为2。如果不减一,那么你会更新7,8,9,你会发现代价为0,而实际上代价为1,所以减一就是防止这种情况。

#include<bits/stdc++.h>
#define mid (l + r) / 2
using namespace std;
const int maxn = 2e5 + 10, N = 1e9;
int ls[maxn * 31], rs[maxn * 31], sum[maxn * 31], tag[maxn * 31], cnt;
int p[maxn], h[maxn], x[maxn], y[maxn], ans[maxn];
vector<int> G[maxn];
void pushdown(int o, int l, int r) 
{
    if (tag[o]) {
        if (!ls[o])
            ls[o] = ++cnt;
        if (!rs[o])
            rs[o] = ++cnt;
        tag[ls[o]] = tag[rs[o]] = 1;
        sum[ls[o]] = mid - l + 1;
        sum[rs[o]] = r - mid;
        tag[o] = 0;
    }
}
void up(int &o, int l, int r, int ql, int qr) 
{
    if (sum[o] == r - l + 1)
        return;
    if (!o)
        o = ++cnt;
    if (l >= ql && r <= qr) {
        tag[o] = 1;
        sum[o] = r - l + 1;
        return;
    }
    if(ql>mid) up(rs[o],mid+1,r,ql,qr);
	else if(qr<=mid) up(ls[o],l,mid,ql,qr);
	else {
		up(ls[o],l,mid,ql,qr);
		up(rs[o],mid+1,r,ql,qr);
	}
    sum[o] = sum[ls[o]] + sum[rs[o]] ;
}
int qu(int o, int l, int r, int ql, int qr) 
{
    if (l >= ql && r <= qr)
    return sum[o];
    pushdown(o, l, r);
    int cat = 0;
    if (ql <= mid)
        cat += qu(ls[o], l, mid, ql, qr);
    if (qr > mid)
        cat += qu(rs[o], mid + 1, r, ql, qr);
    return cat ;
}
int main() {
    int n, q, rt = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    scanf("%d%d", &p[i], &h[i]);
    scanf("%d", &q);
    for (int i = 1; i <= q; i++) {
        scanf("%d%d", &x[i], &y[i]);
        G[x[i]].push_back(i);
    }
    for (int i = n; i; i--) {
        up(rt, 1, N, p[i], min(N, p[i] + h[i] - 1));
        for (auto id : G[i])
        ans[id] = p[y[id]] - p[x[id]] - qu(rt, 1, N, p[x[id]], p[y[id]] - 1);
    }
    for (int i = 1; i <= q; i++)
    printf("%d\n", ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值