首先,我们求出对于每一个位置的数 A i A_i Ai,有哪些区间的最大值为 A i A_i Ai,容易发现满足条件的区间的左端点必然位于 [ L i , i ] [L_i,i] [Li,i],右端点必然位于 [ i , R i ] [i,R_i] [i,Ri],使用单调队列可以在 O ( n ) O(n) O(n)下求出所有的 L L L和 R R R。
将所有区间看作一个二维平面,其中区间 [ l , r ] [l,r] [l,r]表示格子 ( l , r ) (l,r) (l,r),注意到位置 i i i将会使得 [ L i , i ] × [ i , R i ] [L_i,i]\times [i,R_i] [Li,i]×[i,Ri]这个矩形区域的最大值为 A i A_i Ai。那么问题变成一个类似求二维区间和的问题,只不过在这个问题里,除了覆盖的矩形,平面上的每个格子也有各自的权值。
考虑离线,我们将左上角
(
a
,
b
)
(a,b)
(a,b)、右下角
(
c
,
d
)
(c,d)
(c,d)的询问拆分成四个二维前缀和的组合,即:
a
n
s
(
a
,
b
,
c
,
d
)
=
a
n
s
(
1
,
1
,
c
,
d
)
−
a
n
s
(
1
,
1
,
c
,
b
−
1
)
−
a
n
s
(
1
,
1
,
a
−
1
,
d
)
+
a
n
s
(
1
,
1
,
a
−
1
,
b
−
1
)
ans(a,b,c,d)=ans(1,1,c,d)-ans(1,1,c,b-1)-ans(1,1,a-1,d)+ans(1,1,a-1,b-1)
ans(a,b,c,d)=ans(1,1,c,d)−ans(1,1,c,b−1)−ans(1,1,a−1,d)+ans(1,1,a−1,b−1)
但是我们不能像BZOJ4262一样直接将其排序后线段树离线处理,因为在非随机序列中,我们无法保证插入的线段条数的界。
接下来我们继续将每个产生贡献的矩形拆分成四个二维后缀和的组合,那么此时我们可以计算每个贡献后缀对每个查询前缀产生的影响,而只有当查询 ( c , d ) (c,d) (c,d)与贡献 ( a , b ) (a,b) (a,b)满足 c ≥ a , d ≥ b c\ge a,d\ge b c≥a,d≥b时,后者才会对前者产生影响。这使得我们容易想到固定一维之后从前往后处理在每一个询问受到的影响。
那么如果贡献
(
a
,
b
)
(a,b)
(a,b)的最大值为
x
x
x,其对查询
(
c
,
d
)
(c,d)
(c,d)产生的影响为:
x
∑
i
=
a
c
∑
j
=
b
d
(
j
−
i
+
1
)
x\sum_{i=a}^c\sum_{j=b}^d(j-i+1)
x∑i=ac∑j=bd(j−i+1)
=
x
(
g
(
c
,
d
)
−
g
(
c
,
b
−
1
)
−
g
(
a
−
1
,
d
)
+
g
(
a
−
1
,
b
−
1
)
)
=x(g(c,d)-g(c,b-1)-g(a-1,d)+g(a-1,b-1))
=x(g(c,d)−g(c,b−1)−g(a−1,d)+g(a−1,b−1))
其中
g
(
a
,
b
)
=
∑
i
=
1
a
∑
j
=
1
b
j
−
i
+
1
g(a,b)=\sum_{i=1}^a\sum_{j=1}^bj-i+1
g(a,b)=∑i=1a∑j=1bj−i+1,
而
g
(
a
,
b
)
=
∑
i
=
1
a
∑
j
=
1
b
j
−
i
+
1
=
(
1
+
b
)
b
2
a
−
(
1
+
a
)
a
2
b
+
a
b
g(a,b)=\sum_{i=1}^a\sum_{j=1}^bj-i+1=\frac {(1+b)b}2a-\frac {(1+a)a} 2b+ab
g(a,b)=∑i=1a∑j=1bj−i+1=2(1+b)ba−2(1+a)ab+ab,故我们维护
x
,
g
(
a
−
1
,
b
−
1
)
x
,
(
a
−
1
)
x
,
(
b
−
1
)
x
,
b
(
b
−
1
)
2
x
,
a
(
a
−
1
)
2
x
x,g(a-1,b-1)x,(a-1)x,(b-1)x,\frac {b(b-1)}2x,\frac {a(a-1)}2x
x,g(a−1,b−1)x,(a−1)x,(b−1)x,2b(b−1)x,2a(a−1)x的前缀和即可快速计算出每个查询受到的影响。
说下实现的部分,因为答案有可能超longlong,所以用__int128是个安全的选择,同时因为空间卡得非常紧,可以将离线分成多次处理,只使用1个或者2个树状数组维护,有效降低空间压力。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
using namespace std;
//--Container
//--
#define clr(a) memset(a,0,sizeof(a))
typedef __int128 ll;
const int up=1e5;
int n,m,ar[up+10],que[up+10][2],qn,alr[up+10][2];ll rs[up+10],zrs[up*4+10];
struct ice{
int a,b,ip,rid,val;char sty;
}iar[up*8+10];int icn;
bool idmp(const ice&a,const ice&b){
return a.a==b.a?a.sty<b.sty:a.a<b.a;
};
void psh(int sty,int a,int b,int ip,ll val){
iar[icn].a=a,iar[icn].b=b,iar[icn].ip=ip,iar[icn].sty=sty,iar[icn].val=val;++icn;
};
ll te[up+10],ge[up+10];
inline int lw(int n){return n&-n;};
void upd(ll*te,int d,ll x){
for(;d<=up;d+=lw(d))te[d]+=x;
};
ll qryy(ll*te,int d){
ll rs=0;for(;d;d-=lw(d))rs+=te[d];return rs;
};
inline ll _gg(ll a,ll b){
return ((1+b)*b/2)*a-((1+a)*a/2)*b+a*b;
};
void _cl(){
int i,j,k,d,t;
for(clr(te),i=0;i<icn;++i)if(iar[i].a>0&&iar[i].b>0){
if(!iar[i].sty){
upd(te,iar[i].b,iar[i].val);
}
else{
zrs[iar[i].rid]+=qryy(te,iar[i].b)*_gg(iar[i].a,iar[i].b);
}
}
for(clr(te),i=0;i<icn;++i)if(iar[i].a>0&&iar[i].b>0){
if(!iar[i].sty){
if(iar[i].a>1&&iar[i].b>1)
upd(te,iar[i].b,_gg(iar[i].a-1,iar[i].b-1)*iar[i].val);
}
else{
zrs[iar[i].rid]+=qryy(te,iar[i].b);
}
}
for(clr(te),i=0;i<icn;++i)if(iar[i].a>0&&iar[i].b>0){
if(!iar[i].sty){
if(iar[i].a>1){
ll zt=(ll)iar[i].a*(iar[i].a-1)/2;
upd(te,iar[i].b,zt*iar[i].val);
upd(ge,iar[i].b,(ll)iar[i].val*(iar[i].a-1));
}
}
else{
ll zt=qryy(ge,iar[i].b),gt=(ll)iar[i].b*(1+iar[i].b)/2;
zrs[iar[i].rid]+=(qryy(te,iar[i].b)*iar[i].b-gt*zt-zt*iar[i].b);
}
}
for(clr(te),clr(ge),i=0;i<icn;++i)if(iar[i].a>0&&iar[i].b>0){
if(!iar[i].sty){
if(iar[i].b>1){
ll zt=(ll)iar[i].b*(iar[i].b-1)/2;
upd(te,iar[i].b,zt*iar[i].val);
upd(ge,iar[i].b,(ll)iar[i].val*(iar[i].b-1));
}
}
else{
ll zt=qryy(ge,iar[i].b),gt=(ll)iar[i].a*(1+iar[i].a)/2;
zrs[iar[i].rid]+=(gt*zt-qryy(te,iar[i].b)*iar[i].a-zt*iar[i].a);
}
}
};
void _out(ll x){
if(x>9)_out(x/10);
putchar(x%10+'0');
};
bool cl(){
int i,j,k,t;if(scanf("%d %d",&n,&m)==-1)return 0;for(i=1;i<=n;scanf("%d",&ar[i++]));
for(qn=0,que[0][0]=0,que[0][1]=up+10,i=1;i<=n;++i){
for(;que[qn][1]<ar[i];--qn);alr[i][0]=que[qn][0]+1;
++qn;que[qn][0]=i,que[qn][1]=ar[i];
}
for(qn=0,que[0][0]=n+1,que[0][1]=up+10,i=n;i;--i){
for(;que[qn][1]<=ar[i];--qn);alr[i][1]=que[qn][0]-1;
++qn;que[qn][0]=i,que[qn][1]=ar[i];
}
for(icn=0,i=1;i<=n;++i){
int a=alr[i][0],b=alr[i][1];
psh(0,a,i,-1,ar[i]);
psh(0,i+1,b+1,-1,ar[i]);
psh(0,i+1,i,-1,-ar[i]);
psh(0,a,b+1,-1,-ar[i]);
}
for(i=0,t=0;i<m;++i){
int a,b,c,d;scanf("%d %d %d %d",&a,&b,&c,&d);
iar[icn].rid=t++;psh(1,b,d,i,1);
iar[icn].rid=t++;psh(1,a-1,c-1,i,1);
iar[icn].rid=t++;psh(1,b,c-1,i,-1);
iar[icn].rid=t++;psh(1,a-1,d,i,-1);
}
for(i=0;i<t;zrs[i++]=0);
sort(iar,iar+icn,idmp);_cl();for(clr(rs),i=0;i<icn;++i)if(iar[i].sty){
rs[iar[i].ip]+=zrs[iar[i].rid]*iar[i].val;
}
for(i=0;i<m;++i){_out(rs[i]);putchar('\n');}
return 1;
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
while(cl());
return 0;
};