【学习笔记/模板】吉司机线段树
吉司机线段树
前言
吉司机线段树,是吉如一老师在国家队论文中提出的一种线段树,可以实现区间修改取 \(\min/\max\) 和记录历史最大/最小值的操作。
例题:
P6242 【模板】线段树 3
这道例题基本上涵盖了吉司机线段树的经典操作,其 \(B\) 数组其实就是记录了 \(A\) 数组的历史最大值。
所以五个操作就是:
操作 | 概述 |
---|---|
1 | 区间加法 |
2 | 区间修改为最小值 |
3 | 区间求和 |
4 | 区间查询最大值 |
5 | 区间查询历史最大值 |
作为进阶版本的线段树,其节点维护的值也有所增加。我们先介绍一遍他们,作用且按下不表。
struct Tree{
int l, r;
LL sum;
LL max_st, max_nd, max_his;
LL num_max;
LL lazy_st, lazy_sth, lazy_nd, lazy_ndh;
}tr[MAXN << 2];
\(l\),\(r\):区间左右端点;
\(sum\):区间所有元素的和;
\(maxst\):区间的最大值;
\(maxnd\):区间的严格次大值;
\(maxhis\):区间的历史最大值;
\(nummax\):区间最大值出现的次数;
\(lazyst\):区间最大值的加减标记;
\(lazysth\):区间历史最大值的加减标记;
\(lazynd\):区间非最大值的加减标记;
\(lazyndh\):区间非历史最大值的加减标记;
这里,大家可以巧妙的运用 define
,不然就会像某个喜欢把变量名起的贼TM长还不用 define
的神必一样写出一份 \(6.12KB\) 的极为难调的代码。
然后,我们分模块来实现这棵线段树。
建树
建树其实没什么区别,只是叶子节点上没有第二个元素,区间严格次大值赋为 \(-INF\) 即可(代表区间严格次大值为空,方便以后更新)。
void Build(int rt, int l, int r){
tr[rt].l = l;
tr[rt].r = r;
if(l == r){
tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l];
tr[rt].num_max = 1;
tr[rt].max_nd = -INF;
return;
}
int mid = (l + r) >> 1;
Build(lson(rt), l, mid);
Build(rson(rt), mid + 1, r);
Pushup(rt);
}
pushup
pushup
会更新当前节点的 \(sum,maxst,maxnd,maxhis,nummax\)。
\(sum\) 是左右儿子的加和。
\(maxst,maxhis\) 肯定是左右儿子中大的那一个。
\(nummax\) 需要分类讨论:
-
左右儿子的 \(maxst\) 相同时,\(nummax\) 就是左右儿子的 \(nummax\) 的和;
-
否则,\(nummax\) 是左右儿子中 \(maxst\) 大的那个的 \(nummax\)。
\(maxnd\) 同理:
-
左右儿子的 \(maxst\) 相同时,\(maxnd\) 就是左右儿子的 \(maxnd\) 中大的那个;
-
否则,\(maxnd\) 是 \(maxst\) 小的那个儿子的 \(maxst\) 于 \(maxst\) 大的那个儿子的 \(maxnd\) 中大的那个。
inline void Pushup(int rt){
tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum;
tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
if(tr[lson(rt)].max_st == tr[rson(rt)].max_st){
tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);
}
else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st){
tr[rt].num_max = tr[lson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);
}
else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st){
tr[rt].num_max = tr[rson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);
}
}
你不写 define
现在行宽都TM成什么样了。
pushdown
额,这里算是个难点吧,方便理解同时减少码量(你还好意思说减少码量),我们把懒标记的下方拆成两个函数 Modify
和 Pushdown
。
先看 Modify
:
\(valst\):区间最大值加上的数;
\(valsth\):区间历史最大值加上的数;
\(valnd\):区间非最大值加上的数;
\(valndh\):区间历史非最大值加上的数。
变量名怎么又怎么长!
-
更新 \(sum\),把区间最大值的个数乘上 \(valst\),其他的数的个数乘上 \(valnd\),他们的和即为 \(sum\) 的新增部分。
-
更新 \(maxhis\),此时,未更新的 \(maxst\) 也成为了“历史”,所以 \(maxhis\) 是 \(maxhis\) 于 \(maxst + valsth\) 的最大值。
-
更新 \(maxst\),直接加上 \(val_st\) 就行了。
-
更新 \(maxnd\),如果这个区间有 \(maxnd\),即 \(maxnd ≠ -INF\),加上 \(valnd\)。
之后我们更新懒标记,(捏麻麻地变量名起这么长写博客都难写)。
-
更新 \(lazysth\),此时,为更新的 \(lazyst\) 也和 \(maxst\) 一样,成为了“历史”,\(lazysth\) 的值也就是 \(lazysth\) 与 \(lazyst + valsth\) 的最大值;
-
更新 \(lazyst\),直接加;
-
更新 \(lazyndh\),\(lazyndh\) 与 \(lazynd + valndh\) 的最大值,理由同 \(lazysth\);
-
更新 \(lazyndh\),直接加。
值得注意的是更新的顺序问题,先更新历史最值,在更新当前的最值。
inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
tr[rt].max_st += val_st;
if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;
tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth);
tr[rt].lazy_st += val_st;
tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh);
tr[rt].lazy_nd += val_nd;
}
更TM的宽了艹。
然后是 Pushdown
:
当一个儿子的最大值等于当前区间的最大值时,这个子节点就要以更新最大值来更新。反之则以非最大值来更新。
值得注意的是,不能每次在判断时比较两个子节点的 \(maxst\) 的大小,要提前记录,因为有一个子节点已经被先行更新了。
inline void Pushdown(int rt){
int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
if(tr[lson(rt)].max_st == maxn)
Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
if(tr[rson(rt)].max_st == maxn)
Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
}
Update_Add
对应操作 \(1\),把所有数都加上 \(k\) 的话直接 Modify(rt, k, k, k, k)
就行了。
void Update_Add(int rt, int l, int r, LL val){
if(tr[rt].l >= l && tr[rt].r <= r){
Modify(rt, val, val, val, val);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Add(lson(rt), l, r, val);
if(r > mid) Update_Add(rson(rt), l, r, val);
Pushup(rt);
}
Update_Min
对应操作 \(2\),将区间 \([l, r]\) 中的 \(A_{i}\) 都变成 \(\min (A_{i},v)\)。
显然,当区间的 \(maxst ≥ v\) 的话,就可以直接 return
润了,然后继续递归?
然后就假掉了,当 \(v\) 很小的时候,复杂度直接卡满,还记得我们维护的区间严格次大值吗,这时候他就排上用场了。
我们找到一个 \(maxst > v\) 但 \(maxnd < v\) 的区间,然后只用更改区间的最大值就行了,取 \(\min\) 的操作可以传化成减法。
void Update_Min(int rt, int l, int r, LL val){
if(tr[rt].max_st <= val) return;
if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val){
Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Min(lson(rt), l, r, val);
if(r > mid) Update_Min(rson(rt), l, r, val);
Pushup(rt);
}
剩下的查询和普通线段树一样,不用讲,直接给代码吧。
LL Query_Sum(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].sum;
Pushdown(rt);
LL ans = 0;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans += Query_Sum(lson(rt), l, r);
if(r > mid) ans += Query_Sum(rson(rt), l, r);
return ans;
}
LL Query_Max(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_st;
Pushdown(rt);
LL ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));
return ans;
}
LL Query_His(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_his;
Pushdown(rt);
LL ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));
return ans;
}
Code
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const LL INF = 1e18;
const int MAXN = 5e5 + 10;
int n, m;
LL num[MAXN];
inline LL read(){
LL x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
struct Segment_Tree{
struct Tree{
int l, r;
LL sum;
LL max_st, max_nd, max_his;
LL num_max;
LL lazy_st, lazy_sth, lazy_nd, lazy_ndh;
}tr[MAXN << 2];
inline int lson(int rt){
return rt << 1;
}
inline int rson(int rt){
return rt << 1 | 1;
}
inline void Pushup(int rt){
tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum;
tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
if(tr[lson(rt)].max_st == tr[rson(rt)].max_st){
tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);
}
else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st){
tr[rt].num_max = tr[lson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);
}
else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st){
tr[rt].num_max = tr[rson(rt)].num_max;
tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);
}
}
void Build(int rt, int l, int r){
tr[rt].l = l;
tr[rt].r = r;
if(l == r){
tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l];
tr[rt].num_max = 1;
tr[rt].max_nd = -INF;
return;
}
int mid = (l + r) >> 1;
Build(lson(rt), l, mid);
Build(rson(rt), mid + 1, r);
Pushup(rt);
}
inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
tr[rt].max_st += val_st;
if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;
tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth);
tr[rt].lazy_st += val_st;
tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh);
tr[rt].lazy_nd += val_nd;
}
inline void Pushdown(int rt){
int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
if(tr[lson(rt)].max_st == maxn)
Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
if(tr[rson(rt)].max_st == maxn)
Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
}
void Update_Add(int rt, int l, int r, LL val){
if(tr[rt].l >= l && tr[rt].r <= r){
Modify(rt, val, val, val, val);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Add(lson(rt), l, r, val);
if(r > mid) Update_Add(rson(rt), l, r, val);
Pushup(rt);
}
void Update_Min(int rt, int l, int r, LL val){
if(tr[rt].max_st <= val) return;
if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val){
Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Min(lson(rt), l, r, val);
if(r > mid) Update_Min(rson(rt), l, r, val);
Pushup(rt);
}
LL Query_Sum(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].sum;
Pushdown(rt);
LL ans = 0;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans += Query_Sum(lson(rt), l, r);
if(r > mid) ans += Query_Sum(rson(rt), l, r);
return ans;
}
LL Query_Max(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_st;
Pushdown(rt);
LL ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));
return ans;
}
LL Query_His(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_his;
Pushdown(rt);
LL ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));
return ans;
}
}S;
int main(){
n = read(), m = read();
for(register int i = 1; i <= n; i++)
num[i] = read();
S.Build(1, 1, n);
for(register int i = 1; i <= m; i++){
int opt;
opt = read();
if(opt == 1){
int l, r, k;
l = read(), r = read(), k = read();
S.Update_Add(1, l, r, k);
}
else if(opt == 2){
int l, r, v;
l = read(), r = read(), v = read();
S.Update_Min(1, l, r, v);
}
else if(opt == 3){
int l, r;
l = read(), r = read();
printf("%lld\n", S.Query_Sum(1, l, r));
}
else if(opt == 4){
int l, r;
l = read(), r = read();
printf("%lld\n", S.Query_Max(1, l, r));
}
else{
int l, r;
l = read(), r = read();
printf("%lld\n", S.Query_His(1, l, r));
}
}
return 0;
}
你怎么TMD变量名这么长还就是不写宏定义啊
P4314 CPU 监控
Code
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 10;
const int INF = 2147483647;
int t, e;
int num[MAXN];
inline int read(){
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
struct Segment_Tree{
struct Tree{
int l, r;
int max_st, max_his; //区间最大值,历史区间最大值
int lazy_st_add, lazy_sth_add; //区间加的懒标记,区间加的历史最大值的懒标记
int lazy_st_cov, lazy_sth_cov; //区间覆盖的懒标记,区间的历史最大值的最大覆盖的懒标记
Tree(){
lazy_st_add = lazy_sth_add = 0;
lazy_st_cov = lazy_sth_cov = -INF;
}
}tr[MAXN << 2];
inline int lson(int rt){
return rt << 1;
}
inline int rson(int rt){
return rt << 1 | 1;
}
inline void Pushup(int rt){
tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
}
void Build(int rt, int l, int r){
tr[rt].l = l;
tr[rt].r = r;
if(l == r){
tr[rt].max_st = tr[rt].max_his = num[l];
return;
}
int mid = (l + r) >> 1;
Build(lson(rt), l, mid);
Build(rson(rt), mid + 1, r);
Pushup(rt);
}
inline void Modify_Add(int rt, int val_st, int val_sth){
tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
tr[rt].max_st += val_st;
if(tr[rt].lazy_st_cov == -INF){
tr[rt].lazy_sth_add = max(tr[rt].lazy_sth_add, tr[rt].lazy_st_add + val_sth);
tr[rt].lazy_st_add += val_st;
}
else{
tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, tr[rt].lazy_st_cov + val_sth);
tr[rt].lazy_st_cov += val_st;
}
}
inline void Modify_Cov(int rt, int val_st, int val_sth){
tr[rt].max_st = val_st;
tr[rt].max_his = max(tr[rt].max_his, val_sth);
tr[rt].lazy_st_cov = val_st;
tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, val_sth);
}
inline void Pushdown(int rt){
if(tr[rt].lazy_st_add || tr[rt].lazy_sth_add){
Modify_Add(lson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
Modify_Add(rson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
tr[rt].lazy_st_add = tr[rt].lazy_sth_add = 0;
}
if(tr[rt].lazy_st_cov != -INF || tr[rt].lazy_sth_cov != -INF){
Modify_Cov(lson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
Modify_Cov(rson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
tr[rt].lazy_st_cov = tr[rt].lazy_sth_cov = -INF;
}
}
void Update_Add(int rt, int l, int r, int val){
if(tr[rt].l >= l && tr[rt].r <= r){
Modify_Add(rt, val, val);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Add(lson(rt), l, r, val);
if(r > mid) Update_Add(rson(rt), l, r, val);
Pushup(rt);
}
void Update_Cov(int rt, int l, int r, int val){
if(tr[rt].l >= l && tr[rt].r <= r){
Modify_Cov(rt, val, val);
return;
}
Pushdown(rt);
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Cov(lson(rt), l, r, val);
if(r > mid) Update_Cov(rson(rt), l, r, val);
Pushup(rt);
}
int Query_Max(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_st;
Pushdown(rt);
int ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));
return ans;
}
int Query_His(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].max_his;
Pushdown(rt);
int ans = -INF;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));
return ans;
}
}S;
int main(){
t = read();
for(register int i = 1; i <= t; i++)
num[i] = read();
S.Build(1, 1, t);
e = read();
for(register int i = 1; i <= e; i++){
char opt[5];
scanf("%s", opt + 1);
if(opt[1] == 'Q'){
int l, r;
l = read(), r = read();
printf("%d\n", S.Query_Max(1, l, r));
}
else if(opt[1] == 'A'){
int l, r;
l = read(), r = read();
printf("%d\n", S.Query_His(1, l, r));
}
else if(opt[1] == 'P'){
int l, r, v;
l = read(), r = read(), v = read();
S.Update_Add(1, l, r, v);
}
else if(opt[1] == 'C'){
int l, r, v;
l = read(), r = read(), v = read();
S.Update_Cov(1, l, r, v);
}
}
return 0;
}
你TM怎么还是不写宏定义啊。
update at 2022.9.25
Silver_Ash嫌我代码太长,所以提供一个(他喜欢的)压行的。
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const LL INF = 1e18; const int MAXN = 5e5 + 10;
int n, m; LL num[MAXN];
inline LL read(){
LL x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9' ) {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
return x * f;
}
struct Segment_Tree{
struct Tree {int l, r; LL sum, max_st, max_nd, max_his, num_max, lazy_st, lazy_sth, lazy_nd, lazy_ndh;}tr[MAXN << 2];
inline int lson(int rt) {return rt << 1;}
inline int rson(int rt) {return rt << 1 | 1;}
inline void Pushup(int rt){
tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum; tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st); tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
if(tr[lson(rt)].max_st == tr[rson(rt)].max_st) {tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);}
else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st) {tr[rt].num_max = tr[lson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);}
else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st) {tr[rt].num_max = tr[rson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);}
}
void Build(int rt, int l, int r){
tr[rt].l = l; tr[rt].r = r;
if(l == r) {tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l]; tr[rt].num_max = 1; tr[rt].max_nd = -INF; return;}
int mid = (l + r) >> 1; Build(lson(rt), l, mid); Build(rson(rt), mid + 1, r); Pushup(rt);
}
inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth); tr[rt].max_st += val_st;
if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;
tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth); tr[rt].lazy_st += val_st;
tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh); tr[rt].lazy_nd += val_nd;
}
inline void Pushdown(int rt){
int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
if(tr[lson(rt)].max_st == maxn) Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
if(tr[rson(rt)].max_st == maxn) Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
}
void Update_Add(int rt, int l, int r, LL val){
if(tr[rt].l >= l && tr[rt].r <= r) {Modify(rt, val, val, val, val); return;}
Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Add(lson(rt), l, r, val); if(r > mid) Update_Add(rson(rt), l, r, val); Pushup(rt);
}
void Update_Min(int rt, int l, int r, LL val){
if(tr[rt].max_st <= val) return;
if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val) {Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0); return;}
Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Min(lson(rt), l, r, val); if(r > mid) Update_Min(rson(rt), l, r, val); Pushup(rt);
}
LL Query_Sum(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].sum;
Pushdown(rt); LL ans = 0; int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans += Query_Sum(lson(rt), l, r); if(r > mid) ans += Query_Sum(rson(rt), l, r); return ans;
}
LL Query_Max(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_st;
Pushdown(rt); LL ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r)); return ans;
}
LL Query_His(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_his;
Pushdown(rt); LL ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_His(rson(rt), l, r)); return ans;
}
}S;
int main(){
n = read(), m = read();
for(register int i = 1; i <= n; i++) num[i] = read();
S.Build(1, 1, n);
for(register int i = 1; i <= m; i++){
int opt = read();
if(opt == 1) {int l, r, k; l = read(), r = read(), k = read(); S.Update_Add(1, l, r, k);}
else if(opt == 2) {int l, r, v; l = read(), r = read(), v = read(); S.Update_Min(1, l, r, v);}
else if(opt == 3) {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_Sum(1, l, r));}
else if(opt == 4) {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_Max(1, l, r));}
else {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_His(1, l, r));}
}
return 0;
}
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 10; const int INF = 2147483647;
int t, e, num[MAXN];
inline int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
return x * f;
}
struct Segment_Tree{
struct Tree{
int l, r; int max_st, max_his, lazy_st_add, lazy_sth_add, lazy_st_cov, lazy_sth_cov;
Tree() {lazy_st_add = lazy_sth_add = 0; lazy_st_cov = lazy_sth_cov = -INF;}
}tr[MAXN << 2];
inline int lson(int rt) {return rt << 1;}
inline int rson(int rt) {return rt << 1 | 1;}
inline void Pushup(int rt){ tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st); tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);}
void Build(int rt, int l, int r){
tr[rt].l = l; tr[rt].r = r;
if(l == r){ tr[rt].max_st = tr[rt].max_his = num[l]; return;}
int mid = (l + r) >> 1; Build(lson(rt), l, mid); Build(rson(rt), mid + 1, r); Pushup(rt);
}
inline void Modify_Add(int rt, int val_st, int val_sth){
tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth); tr[rt].max_st += val_st;
if(tr[rt].lazy_st_cov == -INF) {tr[rt].lazy_sth_add = max(tr[rt].lazy_sth_add, tr[rt].lazy_st_add + val_sth); tr[rt].lazy_st_add += val_st;}
else {tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, tr[rt].lazy_st_cov + val_sth); tr[rt].lazy_st_cov += val_st;}
}
inline void Modify_Cov(int rt, int val_st, int val_sth){
tr[rt].max_st = val_st; tr[rt].max_his = max(tr[rt].max_his, val_sth);
tr[rt].lazy_st_cov = val_st; tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, val_sth);
}
inline void Pushdown(int rt){
if(tr[rt].lazy_st_add || tr[rt].lazy_sth_add){
Modify_Add(lson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add); Modify_Add(rson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
tr[rt].lazy_st_add = tr[rt].lazy_sth_add = 0;
}
if(tr[rt].lazy_st_cov != -INF || tr[rt].lazy_sth_cov != -INF){
Modify_Cov(lson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov); Modify_Cov(rson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
tr[rt].lazy_st_cov = tr[rt].lazy_sth_cov = -INF;
}
}
void Update_Add(int rt, int l, int r, int val){
if(tr[rt].l >= l && tr[rt].r <= r) {Modify_Add(rt, val, val); return;}
Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Add(lson(rt), l, r, val); if(r > mid) Update_Add(rson(rt), l, r, val); Pushup(rt);
}
void Update_Cov(int rt, int l, int r, int val){
if(tr[rt].l >= l && tr[rt].r <= r) {Modify_Cov(rt, val, val); return;}
Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update_Cov(lson(rt), l, r, val); if(r > mid) Update_Cov(rson(rt), l, r, val); Pushup(rt);
}
int Query_Max(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_st;
Pushdown(rt); int ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r)); return ans;
}
int Query_His(int rt, int l, int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_his;
Pushdown(rt); int ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_His(rson(rt), l, r)); return ans;
}
}S;
int main(){
t = read(); for(register int i = 1; i <= t; i++) num[i] = read();
S.Build(1, 1, t); e = read();
for(register int i = 1; i <= e; i++){
char opt[5]; scanf("%s", opt + 1);
if(opt[1] == 'Q') {int l, r; l = read(), r = read(); printf("%d\n", S.Query_Max(1, l, r));}
else if(opt[1] == 'A') {int l, r; l = read(), r = read(); printf("%d\n", S.Query_His(1, l, r));}
else if(opt[1] == 'P') {int l, r, v; l = read(), r = read(), v = read(); S.Update_Add(1, l, r, v);}
else if(opt[1] == 'C') {int l, r, v; l = read(), r = read(), v = read(); S.Update_Cov(1, l, r, v);}
}
return 0;
}
就离谱,我把换行和缩进删了码量直接减少2KB
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16720977.html