牛客练习赛56 D.小翔和泰拉瑞亚 线段树

原题链接:https://ac.nowcoder.com/acm/contest/3566/D

题意

有n个数组成的序列,你有m种操作,每次选择 [ l , r ] [l,r] [l,r]区间减去w,你可以从m次操作中任意选择一些操作完成,求完成后整个序列的最大最小值之差最大是多少

分析

首先可以枚举每个数,尽量使它的值减少,用掉所有包含该位置的操作,然后求出全局的最高位置,用最高位置与当前枚举到的位置的高度差来更新答案。这样必定能够求到最优解。因此我们对询问按照左端点进行排序,当操作区间左端点小于当前位置就加入该区间到堆中,最后我们看堆顶的区间右端点是否小于当前位置,小于就直接出堆,每个位置更新一次答案,保证最优性。

Code

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 998244353;
struct node {
    int l, r;
    ll maxx, minn, tag;
}t[N<<2];
int a[N];
void push_up(int u) {
    t[u].maxx = max(t[u<<1].maxx, t[u<<1|1].maxx);
    t[u].minn = min(t[u<<1].minn, t[u<<1|1].minn);
}
void push_down(int u) {
    if (t[u].tag) {
        t[u<<1].tag += t[u].tag;
        t[u<<1|1].tag += t[u].tag;
        t[u<<1].maxx += t[u].tag;
        t[u<<1|1].maxx += t[u].tag;
        t[u<<1].minn += t[u].tag;
        t[u<<1|1].minn += t[u].tag;
        t[u].tag = 0;
        return;
    }
}
void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r, t[u].maxx = -1e18, t[u].minn = 1e18;
    if (l == r) {
        t[u].maxx = t[u].minn = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid+1, r);
    push_up(u);
}
void modify(int u, int ql, int qr, int val) {
    if (ql <= t[u].l && qr >= t[u].r) {
        t[u].maxx += val;
        t[u].minn += val;
        t[u].tag += val;
        return;
    }
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    if (ql <= mid) modify(u<<1, ql, qr, val);
    if (qr > mid) modify(u<<1|1, ql, qr, val);
    push_up(u);
}
ll query(int u, int ql, int qr) {
    if (ql <= t[u].l && qr >= t[u].r) return t[u].maxx;
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    ll ans = -1e18;
    if (ql <= mid) ans = max(ans, query(u<<1, ql, qr));
    if (qr > mid) ans = max(ans, query(u<<1|1, ql, qr));
    return ans;
}
struct Query {
    int l, r, w;
    bool operator < (const Query &rhs) const {
        return l < rhs.l;
    }
}q[M];
struct Node {
    int l, r, w;
    bool operator < (const Node &rhs) const {
        return r > rhs.r;
    }
};
void solve() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    for (int i = 1; i <= m; i++) cin >> q[i].l >> q[i].r >> q[i].w;
    sort(q+1, q+m+1);
    priority_queue<Node> que;
    int cnt = 1;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        while (q[cnt].l <= i && cnt <= m) {
            modify(1, q[cnt].l, q[cnt].r, -q[cnt].w);
            que.push({q[cnt].l, q[cnt].r, q[cnt].w});
            cnt++;
        }
        ans = max(ans, query(1, 1, n) - query(1, i, i));
        while (que.size() && que.top().r <= i) {
            modify(1, que.top().l, que.top().r, que.top().w), que.pop();
        }
    }
    cout << ans << endl;
}


signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值