传送门
线段树好题。
维护区间加,区间取最大值,维护区间最小值,历史区间最小值。
同样先考虑不用维护历史区间最小值的情况,这个可以参考这道题的解法,维护区间最小和次小值可以解决前两个操作,然后使用历史标记的常规维护方式合并标记更新就行了。
代码:
#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 500005
#define inf 2000000030
using namespace std;
struct Node{int l,r,sn,mn,add,his,his_add,his_mn,f;}T[N<<2];
int n,m,a[N];
inline int read(){
int ans=0,w=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
}
inline int min(int a,int b){
return a<b?a:b;}
inline void pushup(int p){
T[p].his=min(T[lc].his,T[rc].his),T[lc].f=T[rc].f=0,T[p].mn=min(T[lc].mn,T[rc].mn);
T[p].sn=min(T[p].mn==T[lc].mn?T[lc].sn:T[lc].mn,T[p].mn==T[rc].mn?T[rc].sn:T[rc].mn);
if(T[lc].mn==T[p].mn)T[lc].f=1;
if(T[rc].mn==T[p].mn)T[rc].f=1;
}
inline void pushadd(int p,int v){
T[p].his_add=min(T[p].his_add,T[p].add+=v),T[p].sn+=v;
T[p].his=min(T[p].his,T[p].mn+=v),T[p].his_mn=min(T[p].his_mn,T[p].mn);
}
inline void pushset(int p,int v){
if(T[p].mn>=v)return;T[p].mn=v;}
inline void pushdown(int p){
if(T[lc].f)T[lc].his=min(T[lc].his,T[p].his_mn),T[lc].his_mn=min(T[lc].his_mn,T[p].his_mn);
else T[lc].his=min(T[lc].his,T[lc].mn+T[p].hi