给你一个数组,然后要你维护一些东西: 区间加值,区间取最小值,区间求和,区间求最大值,区间求每个位置的历史最大值的最大值。
【模板】线段树 3
题目大意
给你一个数组,然后要你维护一些东西:
区间加值,区间取最小值,区间求和,区间求最大值,区间求每个位置的历史最大值的最大值。
思路
这题的难点在于你操作二取最小值是无法用普通的线段树维护区间和的。
所以就要用到吉司机线段树。
它主要是通过维护第一大和第二大这两个东西,如果大于等于第一个就肯定无法更新,如果大于第二个就只会更新第一大,就弄就好了,否则就递归下去更新。
然后开始讲如何维护:
lsx,rsx:左右儿子
sumx:区间权值和
maxax:区间最大数
secx:区间第二大数
cntx:区间最大数的个数
maxbx:区间历史最大数
add_ax:区间最大值的加法的懒标记
add_a1x:区间的不是最大值的加法的懒标记(因为你要么递归下去搞,要么就搞最大值,所以可以这么维护)
add_bx,add_b1x:同理,不过这个是历史最大值和历史非最大值的懒标记。
然后你考虑怎么维护:
首先是上传:maxa,maxb 直接取最大值,sum 直接加起来,sec,cnt 稍微复杂一点就分类讨论一下即可。
然后是下传:考虑那边是最大值就把下传的最大给它的最大,否则它的最大是这个的非最大(两边的非最大自然都是非最大)
至于怎么给,就是这个线段树的一个难点了。
首先全部加上最大加的乘最大的个数和非最大加的和非最大的个数(非最大的个数用全部减去最大个数)。
然后历史最大要加的加上历史要加的,懒标记也要加上各自的,然后反正就是各自加各自的,具体可以看看这段代码:
然后别的操作都比较好搞了。
代码
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int re, zf; char c;
int read() {
re = 0; zf = 1;
c = getchar(); while (c < '0' || c > '9') {if (c == '-') zf = -zf; c = getchar();}
while (c >= '0' && c <= '9') {
re = (re << 3) + (re << 1) + c - '0';
c = getchar();
}
return zf * re;
}
void writee(ll x) {
if (x > 9) writee(x / 10), x %= 10;
putchar(x + '0');
}
void write(ll x) {
if (x < 0) putchar('-'), x = -x;
writee(x);
putchar('\n');
}
const int N = 500001;
int n, m, a[N], op, l, r, x;
struct XD_tree {
ll sum[N << 2];
int add_a[N << 2], add_b[N << 2], add_a1[N << 2], add_b1[N << 2];
int ls[N << 2], rs[N << 2], maxa[N << 2], sec[N << 2], maxb[N << 2], cnt[N << 2];
void up(int now) {
maxa[now] = max(maxa[now << 1], maxa[now << 1 | 1]);
maxb[now] = max(maxb[now << 1], maxb[now << 1 | 1]);
sum[now] = sum[now << 1] + sum[now << 1 | 1];
if (maxa[now << 1] == maxa[now << 1 | 1]) {
sec[now] = max(sec[now << 1], sec[now << 1 | 1]);
cnt[now] = cnt[now << 1] + cnt[now << 1 | 1];
}
else if (maxa[now << 1] > maxa[now << 1 | 1]) {
sec[now] = max(sec[now << 1], maxa[now << 1 | 1]);
cnt[now] = cnt[now << 1];
}
else {
sec[now] = max(maxa[now << 1], sec[now << 1 | 1]);
cnt[now] = cnt[now << 1 | 1];
}
}
void update(int now, int k1, int k2, int k3, int k4) {
sum[now] += 1ll * k1 * cnt[now] + 1ll * k3 * (rs[now] - ls[now] + 1 - cnt[now]);
maxb[now] = max(maxb[now], maxa[now] + k2);
add_b[now] = max(add_b[now], add_a[now] + k2);
add_b1[now] = max(add_b1[now], add_a1[now] + k4);
maxa[now] += k1; add_a[now] += k1;
if (sec[now] != 1e9) sec[now] += k3; add_a1[now] += k3;
}
void down(int now) {
int x = max(maxa[now << 1], maxa[now << 1 | 1]);
if (maxa[now << 1] == x) update(now << 1, add_a[now], add_b[now], add_a1[now], add_b1[now]);
else update(now << 1, add_a1[now], add_b1[now], add_a1[now], add_b1[now]);
if (maxa[now << 1 | 1] == x) update(now << 1 | 1, add_a[now], add_b[now], add_a1[now], add_b1[now]);
else update(now << 1 | 1, add_a1[now], add_b1[now], add_a1[now], add_b1[now]);
add_a[now] = add_b[now] = add_a1[now] = add_b1[now] = 0;
}
void build(int now, int l, int r) {
ls[now] = l; rs[now] = r;
if (l == r) {
sum[now] = maxa[now] = maxb[now] = a[l];
sec[now] = -1e9; cnt[now] = 1;
return ;
}
int mid = (l + r) >> 1; build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);
up(now);
}
void update_add(int now) {
if (ls[now] > r || rs[now] < l) return ;
if (l <= ls[now] && rs[now] <= r) {
update(now, x, x, x, x); return ;
}
down(now);
update_add(now << 1); update_add(now << 1 | 1);
up(now);
}
void update_min(int now) {
if (ls[now] > r || rs[now] < l || x >= maxa[now]) return ;
if (l <= ls[now] && rs[now] <= r && x > sec[now]) {
update(now, x - maxa[now], x - maxa[now], 0, 0); return ;
}
down(now);
update_min(now << 1); update_min(now << 1 | 1);
up(now);
}
ll get_sum(int now) {
if (ls[now] > r || rs[now] < l) return 0;
if (l <= ls[now] && rs[now] <= r) return sum[now];
down(now);
return get_sum(now << 1) + get_sum(now << 1 | 1);
}
int get_maxa(int now) {
if (ls[now] > r || rs[now] < l) return -1e9;
if (l <= ls[now] && rs[now] <= r) return maxa[now];
down(now); return max(get_maxa(now << 1), get_maxa(now << 1 | 1));
}
int get_maxb(int now) {
if (ls[now] > r || rs[now] < l) return -1e9;
if (l <= ls[now] && rs[now] <= r) return maxb[now];
down(now); return max(get_maxb(now << 1), get_maxb(now << 1 | 1));
}
}T;
int main() {
n = read(); m = read();
for (int i = 1; i <= n; i++) a[i] = read();
T.build(1, 1, n);
while (m--) {
op = read(); l = read(); r = read();
if (op == 1) x = read(), T.update_add(1);
if (op == 2) x = read(), T.update_min(1);
if (op == 3) write(T.get_sum(1));
if (op == 4) write(T.get_maxa(1));
if (op == 5) write(T.get_maxb(1));
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-02-22 【luogu P3690】【模板】Link Cut Tree (动态树)
2021-02-22 【luogu P3384】【模板】轻重链剖分
2021-02-22 【ybt金牌导航5-1-1】【luogu P2590】树的统计
2021-02-22 【ybt金牌导航4-5-1】【luogu P3369】普通平衡树(替罪羊树做法)
2021-02-22 【ybt金牌导航4-4-1】【luogu P2596】维护书架 / 书架 / 无旋式treap模板
2021-02-22 【ybt金牌导航4-3-3】【luogu P2286】宠物收养所
2021-02-22 【ybt金牌导航4-1-1】【luogu P1552】派遣(左偏树模板)