最大值和最小值的问题是独立且相似的,考虑最大值:
考虑离线,设ask(i,l,r)为以1到i为右端点时左端点在区间[l,r]内的区间最大值的和。
从1到n枚举右端点,假设现在是i,那么可以通过单调栈求出最小的j使得[j,i]内a[i]是最大值。
然后左端点在[j,i]区间内的所有区间最大值都应当变为a[i],且所有答案应该加上本身的值。
通过线段树打标记维护,时间复杂度$O(n\log n)$。
对于线段树上每个节点,维护以下信息:
v : 区间内所有数的和
s : 历史上所有v的和
l : 区间长度
a,b,c,d : 标记,分别表示生效之后
v'=a*v+b*l
s'=c*v+d*l+s
#include<cstdio>
#include<algorithm>
#define N 262150
typedef long long ll;
int n,m,i,j,l1,r1,l2,r2,a[N],q[N],t,cnt;ll t1,t2,ans[N];
struct Q{
int i,l,r,p,t;
Q(){}
Q(int _i,int _l,int _r,int _p,int _t){i=_i,l=_l,r=_r,p=_p,t=_t;}
}b[N];
inline bool cmp(const Q&a,const Q&b){return a.i<b.i;}
struct tag{
ll a,b,c,d;
tag(){a=1,b=c=d=0;}
tag(ll _a,ll _b,ll _c,ll _d){a=_a,b=_b,c=_c,d=_d;}
inline bool ex(){return a!=1||b||c||d;}
inline tag operator+(const tag&B){
return tag(a*B.a,b*B.a+B.b,a*B.c+c,d+b*B.c+B.d);
}
}tmp;
struct Node{ll v,s;int l;tag t;}T[N];
inline void add1(int x,tag p){
T[x].s+=p.c*T[x].v+p.d*T[x].l;
T[x].v=p.a*T[x].v+p.b*T[x].l;
T[x].t=T[x].t+p;
}
inline void pb(int x){
if(T[x].t.ex()){
add1(x<<1,T[x].t);
add1(x<<1|1,T[x].t);
T[x].t=tag();
}
}
inline void up(int x){
T[x].v=T[x<<1].v+T[x<<1|1].v;
T[x].s=T[x<<1].s+T[x<<1|1].s;
}
void build(int x,int a,int b){
T[x].v=T[x].s=0,T[x].l=b-a+1,T[x].t=tag();
if(a==b)return;
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void add(int x,int a,int b,int c,int d){
if(c<=a&&b<=d){add1(x,tmp);return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)add(x<<1,a,mid,c,d);
if(d>mid)add(x<<1|1,mid+1,b,c,d);
up(x);
}
ll ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return T[x].s;
pb(x);
int mid=(a+b)>>1;ll t=0;
if(c<=mid)t=ask(x<<1,a,mid,c,d);
if(d>mid)t+=ask(x<<1|1,mid+1,b,c,d);
return up(x),t;
}
int main(){
for(scanf("%d",&m);i<m;i++){
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(l2>1)b[++cnt]=Q(l2-1,l1,r1,i,-1);
b[++cnt]=Q(r2,l1,r1,i,1);
if(n<r1)n=r1;
if(n<r2)n=r2;
}
std::sort(b+1,b+cnt+1,cmp);
for(t1=1023,t2=1025,i=1;i<=n;i++,t1=t1*1023%1000000000,t2=t2*1025%1000000000)a[i]=t1^t2;
for(build(1,1,n),i=j=1;i<=n;q[++t]=i++){
while(t&&a[q[t]]<a[i])t--;
tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0));
while(j<=cnt&&b[j].i==i)ans[b[j].p]+=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++;
}
for(build(1,1,n),t=0,i=j=1;i<=n;q[++t]=i++){
while(t&&a[q[t]]>a[i])t--;
tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0));
while(j<=cnt&&b[j].i==i)ans[b[j].p]-=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++;
}
for(i=0;i<m;i++)printf("%lld\n",ans[i]);
return 0;
}