【学习笔记/模板】吉司机线段树

吉司机线段树

前言

吉司机线段树,是吉如一老师在国家队论文中提出的一种线段树,可以实现区间修改取 \(\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

额,这里算是个难点吧,方便理解同时减少码量(你还好意思说减少码量),我们把懒标记的下方拆成两个函数 ModifyPushdown

先看 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变量名这么长还就是不写宏定义啊

image

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怎么还是不写宏定义啊。

image

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

posted @   TSTYFST  阅读(674)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示