从前有一棵线段树,只会单点加减和单点询问。然后它长大了,会区间加减和区间询问了。它想成为线段树中的国王,但是成为国王的条件是掌握区间取 max 和区间历史最值和两种终极技能,但是它现在并不会,所以需要你的帮助。
给出一个长度为n的序列a,进行m次操作,有4种操作:
- 给出 l,r,x,∀i∈[l,r],ai=max(ai,x)l, r, x, ∀i ∈ [l, r], a_i = \max(a_i, x)l,r,x,∀i∈[l,r],ai=max(ai,x)
- 给出 l,r,x,∀i∈[l,r],ai=ai+xl,r, x, ∀i ∈ [l, r], a_i = a_i + xl,r,x,∀i∈[l,r],ai=ai+x
- 给出 l,r,求∑ai,i∈[l,r]l, r,求∑ a_i , i ∈ [l, r]l,r,求∑ai,i∈[l,r]
- 给出 l,r,求∑bi,i∈[l,r]l,r,求∑ b_i , i ∈ [l, r]l,r,求∑bi,i∈[l,r]
序列𝑏最开始和𝑎相同,每次操作后, ∀𝑖 ∈ [1, 𝑛], 𝑏𝑖 = min(𝑏𝑖, 𝑎𝑖)
题解:
设序列c=a−bc=a-bc=a−b。
对aaa进行吉司机线段树式的维护。
对按照这个位置是否是集合中的最小值对ccc分两类维护吉司机线段树。
然后就没了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;bool f=false;
while(!isdigit(c=gc()))f=c=='-';T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+7,INF=1e9;
int n,m,a[N];
struct node{
int mn,ct,sub,adm,ads,siz;
ll sum;
inline void clear_tag(){adm=ads=0;}
inline void clear(){mn=INF,ct=0,sub=INF+1,siz=0,sum=0;}
inline void init(int v){
adm=ads=0;
if(v==INF)clear();
else mn=v,ct=1,sub=INF,siz=1,sum=v;
}
inline void update(int dm,int ds){
mn+=dm,adm+=dm;
if(sub<INF)sub+=ds,ads+=ds;
sum+=(ll)ct*dm+(ll)(siz-ct)*ds;
}
inline void get(cs node &p){
if(p.mn==mn)ct+=p.ct,sub=std::min(sub,p.sub);
else if(p.mn<mn)sub=std::min(mn,p.sub),mn=p.mn,ct=p.ct;
else sub=std::min(sub,p.mn);
siz+=p.siz,sum+=p.sum;
}
inline void trans(node &p)cs{
if(adm||ads)if(p.mn+adm==mn)p.update(adm,ads);
else p.update(ads,ads);
}
};
namespace SGT{
#define lc u<<1
#define rc u<<1|1
node t1[N<<2],t2[N<<2],t3[N<<2];
inline void pushup(int u){
t1[u].clear(),t2[u].clear(),t3[u].clear();
t1[u].get(t1[lc]),t1[u].get(t1[rc]);
if(t1[u].mn==t1[lc].mn)t2[u].get(t2[lc]);
else t3[u].get(t2[lc]);
if(t1[u].mn==t1[rc].mn)t2[u].get(t2[rc]);
else t3[u].get(t2[rc]);
t3[u].get(t3[lc]);t3[u].get(t3[rc]);
}
inline void pushdown(int u){
t1[u].trans(t1[lc]),t1[u].trans(t1[rc]);
if(t1[u].mn==t1[lc].mn)t2[u].trans(t2[lc]);
else t3[u].trans(t2[lc]);
if(t1[u].mn==t1[rc].mn)t2[u].trans(t2[rc]);
else t3[u].trans(t2[rc]);
t3[u].trans(t3[lc]),t3[u].trans(t3[rc]);
t1[u].clear_tag();t2[u].clear_tag();t3[u].clear_tag();
}
inline void build(int u,int l,int r){
if(l==r){
t1[u].init(a[l]);
t2[u].init(0);
t3[u].init(INF);
return ;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(u);
}
inline void dfs1(int u,int l,int r,int delta,int val){
if(t1[u].mn==val){
if(t2[u].mn>=-delta)t2[u].update(delta,delta);
else if(t2[u].sub>=-delta)t2[u].update(-t2[u].mn,delta);
else {
pushdown(u);
int mid=l+r>>1;
dfs1(lc,l,mid,delta,val);
dfs1(rc,mid+1,r,delta,val);
pushup(u);
}
}
}
inline void dfs2(int u,int l,int r,int val){
if(t1[u].mn>=val)return ;
else if(t1[u].sub>val){
int ad=val-t1[u].mn;
t1[u].update(ad,0);
dfs1(u,l,r,ad,t1[u].mn);
return ;
}
else {
pushdown(u);
int mid=l+r>>1;
dfs2(lc,l,mid,val);
dfs2(rc,mid+1,r,val);
pushup(u);
}
}
inline void modify_max(int u,int l,int r,int ql,int qr,int val){
if(ql<=l&&r<=qr){
dfs2(u,l,r,val);
}
else {
pushdown(u);
int mid=l+r>>1;
if(ql<=mid)modify_max(lc,l,mid,ql,qr,val);
if(mid<qr)modify_max(rc,mid+1,r,ql,qr,val);
pushup(u);
}
}
inline void dfs(int u,int l,int r,int ad,bool f1,bool f2){
if(f1){
if(t2[u].mn>=-ad)t2[u].update(ad,ad),f1=false;
else if(t2[u].sub>=-ad)t2[u].update(-t2[u].mn,ad),f1=false;
}
if(f2){
if(t3[u].mn>=-ad)t3[u].update(ad,ad),f2=false;
else if(t3[u].sub>=-ad)t3[u].update(-t3[u].mn,ad),f2=false;
}
if(f1||f2){
pushdown(u);
int mid=l+r>>1;
dfs(lc,l,mid,ad,t1[lc].mn==t1[u].mn?f1:f2,f2);
dfs(rc,mid+1,r,ad,t1[rc].mn==t1[u].mn?f1:f2,f2);
pushup(u);
}
}
inline void modify_add(int u,int l,int r,int ql,int qr,int ad){
if(ql<=l&&r<=qr){
t1[u].update(ad,ad);
dfs(u,l,r,ad,1,1);
}
else {
pushdown(u);
int mid=l+r>>1;
if(ql<=mid)modify_add(lc,l,mid,ql,qr,ad);
if(mid<qr)modify_add(rc,mid+1,r,ql,qr,ad);
pushup(u);
}
}
inline ll query1(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t1[u].sum;
pushdown(u);
int mid=l+r>>1;
if(qr<=mid)return query1(lc,l,mid,ql,qr);
if(mid<ql)return query1(rc,mid+1,r,ql,qr);
return query1(lc,l,mid,ql,qr)+query1(rc,mid+1,r,ql,qr);
}
inline ll query2(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t1[u].sum-t2[u].sum-t3[u].sum;
pushdown(u);
int mid=l+r>>1;
if(qr<=mid)return query2(lc,l,mid,ql,qr);
if(mid<ql)return query2(rc,mid+1,r,ql,qr);
return query2(lc,l,mid,ql,qr)+query2(rc,mid+1,r,ql,qr);
}
#undef lc
#undef rc
}
signed main(){
#ifdef zxyoi
freopen("sft.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("sft.in","r",stdin);freopen("sft.out","w",stdout);
#endif
#endif
n=gi(),m=gi();
for(int re i=1;i<=n;++i)a[i]=gi();
SGT::build(1,1,n);
while(m--){
switch(gi()){
case 1:{
int l=gi(),r=gi(),x=gi();
SGT::modify_max(1,1,n,l,r,x);
break;
}
case 2:{
int l=gi(),r=gi(),x=gi();
SGT::modify_add(1,1,n,l,r,x);
break;
}
case 3:{
int l=gi(),r=gi();
cout<<SGT::query1(1,1,n,l,r)<<"\n";
break;
}
case 4:{
int l=gi(),r=gi();
cout<<SGT::query2(1,1,n,l,r)<<"\n";
break;
}
}
}
return 0;
}