【模板】线段树 3(区间最值操作、区间历史最值) - 洛谷
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define PII pair<int,int>
#define int long long//当前节点存的懒标记是给下面用的
//spread就是给下面用的时候//我们或许对当前最大值maxa及时的加或减了
//但是没有对maxb做操作,或者说 **某个子区间的maxb可能就没有被更新过**//2024/4/30
//spread -> push_down
//这里保留的是向下更新前这期间的 历史最大的 标记
//
//之前“最值”的做法是错误的,懒标记频繁更新,可能就改不到最大懒标记了。 乱写,
////然后就是min的操作了
//不想一次改到底
//能做到改maxa时就可以停了。
//后续的maxa大于父maxa的就是要调整的
//调整多少呢?我们可以给个懒标记3//2024/5/1
//2操作时,不过确实有多个最大值就错了//你的老二可能比我的牢大大//t3更新的判断有误。可能当前又变了,子节点maxa没变过。
//懂了,其实改,肯定是改大的那个;!!!我们已经递归到只改一个的时候啦!!!
//而且次大值小于修改值,即最大值仍是最大值!//原来最大值的懒标记要分开,是为了更新maxb 。看了良久才看出来
//所以不是最大值(取min操作没取到的)也要统计maxb,所以普通懒标记也需要记录一个本次的最大 。 //区间加u1没有及时更新 maxt1 maxt3
//const int maxn = 5e5 + 5;
const int minv = -5e18;
//int MOD = LLONG_MAX;
class ST//segment tree
{struct node{ll val;//区间和ll maxa;//区间最大值ll seca;//区间次大值ll maxb;//区间历史最大值ll maxn;//最大值数目 用于最大值修改int t1;//加懒标记int maxt1;//不是最大值也要统计maxb,也需要最大懒标记int t2;//乘懒标记int t3;//最大值专属懒标记 VIPint maxt3;//期间最大加懒标记node(int v = 0) :val(v), maxa(0), seca(-2e9), maxb(0), maxn(1),t1(0), maxt1(0), t2(1), t3(0), maxt3(0){}};int n = a.size();vector<ll>a;vector<node>d;void build_tree(int i, int l, int r){if (l == r){d[i].val = d[i].maxa = d[i].maxb = a[l];return;}int mid = l + (r - l) / 2;build_tree(i * 2, l, mid);build_tree(i * 2 + 1, mid + 1, r);push_up(i);}void push_up(int i){d[i].val = (d[i * 2].val + d[i * 2 + 1].val);d[i].maxa = max(d[i * 2].maxa, d[i * 2 + 1].maxa);d[i].maxb = max(d[i * 2].maxb, d[i * 2 + 1].maxb);//不过确实有多个最大值就错了if (d[i * 2].maxa == d[i * 2 + 1].maxa){d[i].seca = max(d[i * 2].seca,d[i*2+1].seca);d[i].maxn = d[i * 2].maxn + d[i * 2 + 1].maxn;}else if (d[i * 2].maxa > d[i * 2 + 1].maxa){d[i].seca = max(d[i*2].seca,d[i * 2 + 1].maxa);d[i].maxn = d[i * 2].maxn;}else// if (d[i * 2].maxa < d[i * 2 + 1].maxa){d[i].seca = max(d[i * 2].maxa, d[i * 2 + 1].seca);d[i].maxn = d[i * 2 + 1].maxn;}}void change(int i, int l, int r, int t1, int maxt1,int t2,int t3, int maxt3){auto& self = d[i];//self.val = self.val * t2;//self.maxa = self.maxa * t2;//self.seca = self.seca * t2;//self.t1 *= t2;//self.t2 *= t2;self.val += t1 * (r - l + 1 - self.maxn) + t3*self.maxn;self.maxb = max(self.maxb, self.maxa + maxt3);self.maxa += t3;if(self.seca != -2e9)self.seca += t1;self.maxt1 = max(self.maxt1, self.t1 + maxt1);self.t1 += t1;self.maxt3 = max(self.maxt3, self.t3 + maxt3);self.t3 += t3;}void push_down(int i,int l,int r){//懒惰int t1 = d[i].t1, maxt1 = d[i].maxt1, t2 = d[i].t2, t3 = d[i].t3, maxt3 = d[i].maxt3;auto& lchild = d[i * 2], &rchild = d[i * 2 + 1];int maxatmp = max(lchild.maxa, rchild.maxa);int mid = l + (r - l) / 2;if (lchild.maxa == maxatmp)change(i*2,l,mid,t1, maxt1, t2,t3,maxt3);elsechange(i*2,l,mid,t1, maxt1, t2,t1,maxt1);//没专属if (rchild.maxa == maxatmp)change(i * 2 + 1, mid + 1, r, t1, maxt1, t2, t3, maxt3);elsechange(i * 2 + 1, mid + 1, r, t1, maxt1, t2, t1, maxt1);//复原d[i].t1 = d[i].maxt1 = d[i].maxt3 = d[i].t3 = 0;d[i].t2 = 1;}ll _getsum(int i, int l, int r, int aiml, int aimr){if (l > aimr || r < aiml)return 0;if (aiml <= l && r <= aimr)return d[i].val;int mid = l + (r - l) / 2;push_down(i,l,r);return _getsum(i * 2, l, mid, aiml, aimr) + _getsum(i * 2 + 1, mid + 1, r, aiml, aimr);}ll _getmaxa(int i, int l, int r, int aiml, int aimr){if (l > aimr || r < aiml)return LLONG_MIN;if (aiml <= l && r <= aimr)return d[i].maxa;int mid = l + (r - l) / 2;push_down(i,l,r);return max(_getmaxa(i * 2, l, mid, aiml, aimr), _getmaxa(i * 2 + 1, mid + 1, r, aiml, aimr));}ll _getmaxb(int i, int l, int r, int aiml, int aimr){if (l > aimr || r < aiml)return LLONG_MIN;if (aiml <= l && r <= aimr)return d[i].maxb;int mid = l + (r - l) / 2;push_down(i,l,r);return max(_getmaxb(i * 2, l, mid, aiml, aimr), _getmaxb(i * 2 + 1, mid + 1, r, aiml, aimr));}void _update1(int i, int l, int r, int aiml, int aimr, ll val){if (l > aimr || r < aiml)return;if (aiml <= l && r <= aimr){d[i].val = (d[i].val + val * (r - l + 1));d[i].maxa = d[i].maxa + val;d[i].maxb = max(d[i].maxb, d[i].maxa);if(d[i].seca != -2e9)d[i].seca += val;d[i].t1 += val;d[i].t3 += val;d[i].maxt1 = max(d[i].maxt1, d[i].t1);d[i].maxt3 = max(d[i].maxt3, d[i].t3);return;}int mid = l + (r - l) / 2;push_down(i,l,r);//因为要向下搜了,所以把当前的懒标记给下面兑现一下_update1(i * 2, l, mid, aiml, aimr, val);_update1(i * 2 + 1, mid + 1, r, aiml, aimr, val);push_up(i);}void _update2(int i, int l, int r, int aiml, int aimr, ll val){if (l > aimr || r < aiml)return;if (aiml <= l && r <= aimr){d[i].val = (d[i].val * val);d[i].t1 = (d[i].t1 * val);d[i].t2 = (d[i].t2 * val);return;}int mid = l + (r - l) / 2;push_down(i,l,r);_update2(i * 2, l, mid, aiml, aimr, val);_update2(i * 2 + 1, mid + 1, r, aiml, aimr, val);push_up(i);}void _update_min(int i, int l, int r, int aiml, int aimr, ll val){if (l > aimr || r < aiml || d[i].maxa <= val)return;if (aiml <= l && r <= aimr && d[i].seca < val){int k = d[i].maxa - val;d[i].val -= d[i].maxn* k;d[i].maxa = val;d[i].t3 -= k;return;}int mid = l + (r - l) / 2;push_down(i, l, r);_update_min(i * 2, l, mid, aiml, aimr, val);_update_min(i * 2 + 1, mid + 1, r, aiml, aimr, val);push_up(i);}
public:ll getsum(int l, int r){return _getsum(1, 1, n, l, r);}ll getmaxa(int l, int r){return _getmaxa(1, 1, n, l, r);}ll getmaxb(int l, int r){return _getmaxb(1, 1, n, l, r);}void update1(int l, int r, ll val){_update1(1, 1, n, l, r, val);//加并挂标记}void update2(int l, int r, ll val){_update2(1, 1, n, l, r, val);//加并挂标记}void update_min(int l, int r, ll val){_update_min(1, 1, n, l, r, val);}ST(vector<ll>arr){a = arr;n = a.size() - 1;d = vector<node>(4 * n);build_tree(1, 1, n);}
};//区间加完,子区间最大值也加
//交汇部分需要再比比signed main()
{ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);int n, m;cin >> n >> m;vector<int>arr(1 + n);for (int i = 1; i <= n; i++)cin >> arr[i];ST demo(arr);for (int i = 0; i < m; i++){int op, l, r, val;cin >> op >> l >> r;switch (op){case 1:cin >> val;demo.update1(l, r, val);break;case 2:cin >> val;demo.update_min(l, r, val);break;case 3:cout << demo.getsum(l, r) << endl;break;case 4:cout << demo.getmaxa(l, r) << endl;break;case 5:cout << demo.getmaxb(l, r) << endl;break;}}return 0;
}