题解:
维护区间最大值mx、最大值出现次数mxcnt、严格次大值semx、最小值mn、最小值出现次数mncnt、严格次小值semn、区间和s、区间加法标记pt、区间最大值相对于其余数字的加法标记mxpt、区间最小值相对于其余数字的加法标记mnpt,一些细节形如:进行朴加法的时候mxpt和mnpt不变;先下传区间加法标记;下传两个最值的标记的时候需要传到最值来源的子树;更新区间最值时,如果发现需要递归左右子树并push_up来得到答案,需要先push_down;注意特判区间最大值等于区间最小值(即所有数字都相等,可以认为是做了一次朴素的加法);注意最大值等于严格次小值或者最小值等于严格次大值(其实本质上都是在说区间只有两类数字的情况,此时以取min为例,若只对区间最大值有影响,而区间最大值等于区间严格次小值,那么在原来的基础上直接对严格次小值进行修改即可)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define gc getchar()
#define N 500010
#define INF (INT_MAX-600000000)
#define inf (INT_MIN+600000000)
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
if(ch^'-') x=ch^'0';else s=-1;
while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return s*x;
}
int a[N];
inline int sgn(int x,int y) { return (x<y)?-1:(x>y); }
struct segment{
int mn,mx,mnpt,mxpt,pt,l,r,semn,semx,mxcnt,mncnt;lint s;segment *ch[2];
}*rt;
inline int push_up(segment* &rt)
{
segment *&l=rt->ch[0],*&r=rt->ch[1];
rt->mnpt=rt->mxpt=rt->pt=0;
rt->s=l->s+r->s;int d;
d=sgn(l->mn,r->mn);
if(d<0) rt->mn=l->mn,rt->mncnt=l->mncnt,rt->semn=min(l->semn,r->mn);
if(d>0) rt->mn=r->mn,rt->mncnt=r->mncnt,rt->semn=min(r->semn,l->mn);
if(d==0) rt->mn=l->mn,rt->mncnt=l->mncnt+r->mncnt,rt->semn=min(l->semn,r->semn);
d=sgn(l->mx,r->mx);
if(d>0) rt->mx=l->mx,rt->mxcnt=l->mxcnt,rt->semx=max(l->semx,r->mx);
if(d<0) rt->mx=r->mx,rt->mxcnt=r->mxcnt,rt->semx=max(r->semx,l->mx);
if(d==0) rt->mx=l->mx,rt->mxcnt=l->mxcnt+r->mxcnt,rt->semx=max(l->semx,r->semx);
return 0;
}
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r,rt->pt=rt->mnpt=rt->mxpt=0;int mid=(l+r)>>1;
if(l==r) return rt->s=rt->mn=rt->mx=a[l],rt->mxcnt=rt->mncnt=1,rt->semn=INF,rt->semx=inf;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);
}
int update(segment* &rt,int s,int t,int v,int tp);
int push_down(segment* &rt);
inline int update_tags(segment* &rt,int x)
{
return rt->pt+=x,rt->mn+=x,rt->mx+=x,rt->semn+=x,rt->semx+=x,rt->s+=(rt->r-rt->l+1ll)*x,0;
}
inline int update_min(segment* &rt,int x)
{
if(x<=rt->mn) return 0;
if(x>=rt->semn)
return push_down(rt),update(rt->ch[0],rt->l,rt->r,x,2),update(rt->ch[1],rt->l,rt->r,x,2),push_up(rt);
int dlt=x-rt->mn;if(rt->mn==rt->mx) return update_tags(rt,dlt);
if(rt->semx==rt->mn) rt->semx+=dlt;
return rt->mnpt+=dlt,rt->mn+=dlt,rt->s+=(lint)dlt*rt->mncnt,0;
}
inline int update_max(segment* &rt,int x)
{
if(x>=rt->mx) return 0;
if(x<=rt->semx)
return push_down(rt),update(rt->ch[0],rt->l,rt->r,x,3),update(rt->ch[1],rt->l,rt->r,x,3),push_up(rt);
int dlt=rt->mx-x;if(rt->mn==rt->mx) return update_tags(rt,-dlt);
if(rt->semn==rt->mx) rt->semn-=dlt;
return rt->mxpt-=dlt,rt->mx-=dlt,rt->s-=(lint)dlt*rt->mxcnt,0;
}
inline int push_down(segment* &rt)
{
if(rt->pt) update_tags(rt->ch[0],rt->pt),update_tags(rt->ch[1],rt->pt),rt->pt=0;
if(rt->mnpt)
{
int d=sgn(rt->ch[0]->mn,rt->ch[1]->mn);
if(d<=0) update_min(rt->ch[0],rt->ch[0]->mn+rt->mnpt);
if(d>=0) update_min(rt->ch[1],rt->ch[1]->mn+rt->mnpt);
rt->mnpt=0;
}
if(rt->mxpt)
{
int d=sgn(rt->ch[0]->mx,rt->ch[1]->mx);
if(d>=0) update_max(rt->ch[0],rt->ch[0]->mx+rt->mxpt);
if(d<=0) update_max(rt->ch[1],rt->ch[1]->mx+rt->mxpt);
rt->mxpt=0;
}
return 0;
}
int update(segment* &rt,int s,int t,int x,int tp)//tp=1,plus; tp=2,x=max(x,v); tp=3,x=min(x,v)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(tp==2&&rt->mn>=x) return 0;
if(tp==3&&rt->mx<=x) return 0;
if(s<=l&&r<=t)
{
if(tp==1) update_tags(rt,x);
if(tp==2) update_min(rt,x);
if(tp==3) update_max(rt,x);
return 0;
}
push_down(rt);
if(s<=mid) update(rt->ch[0],s,t,x,tp);
if(mid<t) update(rt->ch[1],s,t,x,tp);
return push_up(rt);
}
lint query(segment* &rt,int s,int t,int tp)//tp=1,sum; tp=2,max; tp=3,min;
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t)
{
if(tp==1) return rt->s;
if(tp==2) return rt->mx;
if(tp==3) return rt->mn;
}
push_down(rt);lint ans=0;
if(tp==2) ans=inf;
if(tp==3) ans=INF;
if(s<=mid)
{
lint v=query(rt->ch[0],s,t,tp);
if(tp==1) ans+=v;
if(tp==2) ans=max(ans,v);
if(tp==3) ans=min(ans,v);
}
if(mid<t)
{
lint v=query(rt->ch[1],s,t,tp);
if(tp==1) ans+=v;
if(tp==2) ans=max(ans,v);
if(tp==3) ans=min(ans,v);
}
return ans;
}
int main()
{
int n=inn();
for(int i=1;i<=n;i++) a[i]=inn();
build(rt,1,n);
for(int q=inn();q;q--)
{
int tp=inn(),l=inn(),r=inn();
if(tp<=3) update(rt,l,r,inn(),tp);
else printf("%lld\n",query(rt,l,r,tp-3));
}
return 0;
}