H. Skyscraper
题意:给你一个a数组,有m次操作,操作一:对数组a区间[l, r] 加上k,操作二:询问你至少需要几次区间加1,可以使得 h[i] = a[i] (l <= i <= r),每次询问h数组初始值均为0
思路:假设a数组为 1 3 1 4 5,不难发现,我们需要7次区间加1,就可以使得h[i] = a[i] (1 <= i <= n),我们用b数组记录一下a数组的差分值,即 b[i] = a[i] - a[i - 1],且b[i] 为负数时我们把它置0,不难发现b数组:1 2 0 3 1,b数组的总和就是答案,因此我们用线段树维护差分数组就可以了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
struct node {
int L, R, tag;
ll sum;
node operator+(node &t) const {
node tmp;
tmp.L = L;
tmp.R = t.R;
tmp.sum = sum + t.sum;
if (R < t.L)
tmp.sum += t.L - R;
return tmp;
}
}tree[maxn * 4];
void build(int o, int l, int r) {
tree[o].tag = 0;
if (l == r) {
scanf("%d", &tree[o].L);
tree[o].R = tree[o].L;
tree[o].sum = 0;
return;
}
int m = (l + r) / 2, ls = o * 2, rs = o * 2 + 1;
build(ls, l, m);
build(rs, m + 1, r);
tree[o] = tree[ls] + tree[rs];
}
void pushdown(int o, int ls, int rs) {
if (tree[o].tag != 0) {
int tag = tree[o].tag;
tree[ls].tag += tag;
tree[rs].tag += tag;
tree[ls].L += tag; tree[ls].R += tag;
tree[rs].L += tag; tree[rs].R += tag;
tree[o].tag = 0;
}
}
void up(int o, int l, int r, int ql, int qr, int v) {
if (l >= ql && r <= qr) {
tree[o].tag += v;
tree[o].L += v;
tree[o].R += v;
return;
}
int m = (l + r) / 2, ls = o * 2, rs = o * 2 + 1;
pushdown(o, ls, rs);
if (ql <= m)
up(ls, l, m, ql, qr, v);
if (qr > m)
up(rs, m + 1, r, ql, qr, v);
tree[o] = tree[ls] + tree[rs];
}
node qu(int o, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr)
return tree[o];
int m = (l + r) / 2, ls = o * 2, rs = o * 2 + 1;
pushdown(o, ls, rs);
if (qr <= m)
return qu(ls, l, m, ql, qr);
else if (ql > m)
return qu(rs, m + 1, r, ql, qr);
node tmp1 = qu(ls, l, m, ql, qr);
node tmp2 = qu(rs, m + 1, r, ql, qr);
return tmp1 + tmp2;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
build(1, 1, n);
while (m--) {
int opt;
scanf("%d", &opt);
if (opt == 1) {
int ql, qr, x;
scanf("%d%d%d", &ql, &qr, &x);
up(1, 1, n, ql, qr, x);
}
else {
int ql, qr;
scanf("%d%d", &ql, &qr);
node tmp = qu(1, 1, n, ql, qr);
printf("%lld\n", tmp.sum + tmp.L);
}
}
}
}