设询问的下标区间
[
l
,
r
]
[l,r]
[l,r],值域区间
[
x
,
y
]
[x,y]
[x,y],
B
B
B为块大小,下文中的排名是从小到大排
b
l
[
i
]
(
1
≤
i
≤
n
)
bl[i](1\leq i\leq n)
bl[i](1≤i≤n)表示第
i
i
i个位置属于第几个块
L
[
i
]
(
1
≤
i
≤
n
)
L[i](1\leq i\leq n)
L[i](1≤i≤n)表示第
i
i
i块最靠左的是哪个位置
R
[
i
]
(
1
≤
i
≤
n
)
R[i](1\leq i\leq n)
R[i](1≤i≤n)表示第
i
i
i块最靠右的是哪个位置
a
[
i
]
(
1
≤
i
≤
n
)
a[i](1\leq i\leq n)
a[i](1≤i≤n)表示第
i
i
i个数在块内的排名
b
[
i
]
[
j
]
[
k
]
(
0
≤
i
≤
n
B
,
0
≤
j
≤
B
,
0
≤
k
≤
B
)
b[i][j][k](0\leq i\leq \frac nB,0\leq j\leq B,0\leq k\leq B)
b[i][j][k](0≤i≤Bn,0≤j≤B,0≤k≤B)表示仅考虑第
i
i
i块的前
j
j
j个数以及块内值排名小于等于
k
k
k的数的顺序对数量
c
[
i
]
[
j
]
(
0
≤
i
≤
n
B
,
0
≤
j
≤
n
)
c[i][j](0\leq i\leq \frac nB,0\leq j\leq n)
c[i][j](0≤i≤Bn,0≤j≤n)表示前
i
i
i块小于等于
j
j
j的数有多少个
d
[
i
]
(
1
≤
i
≤
n
)
d[i](1\leq i\leq n)
d[i](1≤i≤n)表示把每一块块内排序后现在第
i
i
i个位置的数原来在哪个位置
e
[
i
]
[
j
]
[
k
]
(
0
≤
i
≤
n
B
,
i
<
j
≤
n
B
,
0
≤
k
≤
B
)
e[i][j][k](0\leq i\leq \frac nB,i<j\leq \frac nB,0\leq k\leq B)
e[i][j][k](0≤i≤Bn,i<j≤Bn,0≤k≤B)表示第一个位置位于前
i
i
i块,第二个位置位于第
j
j
j块,且第二个位置在第
j
j
j块块内排名小于等于
k
k
k的顺序对数量
f
[
i
]
[
j
]
[
k
]
(
1
≤
i
≤
n
B
,
0
≤
j
≤
B
,
j
≤
k
≤
B
)
f[i][j][k](1\leq i\leq \frac nB,0\leq j\leq B,j\leq k\leq B)
f[i][j][k](1≤i≤Bn,0≤j≤B,j≤k≤B)表示第
i
i
i块内第一个位置排名大于等于
j
j
j,第二个位置排名小于等于
k
k
k的顺序对数量
r
n
k
(
i
,
j
)
rnk(i,j)
rnk(i,j)表示第
i
i
i块内有多少个数小于等于
j
j
j
我的代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int o=1e5+10,B=330,O=335;
int n,m,p[o],t[o],bl[o],L[o],R[o],a[o],b[O][O][O],c[O][o],d[o],f[O][O][O];long long ans,e[O][O][O];
inline bool cmp(int A,int B){return p[A]<p[B];}
inline int rnk(int Bl,int v){return c[Bl][v]-c[Bl-1][v];}
inline int calc(int l,int r,int x,int y){
int Bl=bl[l];
x=rnk(Bl,x-1)+1;y=rnk(Bl,y);l=l-L[Bl]+1;r=r-L[Bl]+1;
int res=b[Bl][r][y]-b[Bl][l-1][y]-b[Bl][r][x-1]+b[Bl][l-1][x-1],c1=0,c2=0;
for(int i=1;i<l;++i) c1+=(a[i+L[Bl]-1]<x);
for(int i=l;i<=r;++i) c2+=(a[i+L[Bl]-1]>=x&&a[i+L[Bl]-1]<=y);
for(int i=0;i<=y;++i) t[i]=0;
for(int i=1,j;i<l;++i) if((j=a[i+L[Bl]-1])>=x) t[j]=1;
for(int i=1;i<=y;++i) t[i]+=t[i-1];
for(int i=l,j;i<=r;++i) if((j=a[i+L[Bl]-1])<=y) res-=t[j];
for(int i=0;i<=r;++i) t[i]=0;
for(int i=l;i<=r;++i) t[i]=(a[i+L[Bl]-1]<x);
for(int i=1;i<=r;++i) t[i]+=t[i-1];
for(int i=l,j;i<=r;++i) if((j=a[i+L[Bl]-1])>=x&&j<=y) res-=t[i];
return res-c1*c2;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&p[i]),R[bl[i]=i/B+1]=i;
for(int i=n;i;--i) L[bl[i]]=d[i]=i;
for(int i=1;i<=bl[n];++i){
sort(d+L[i],d+R[i]+1,cmp);
for(int j=L[i];j<=R[i];++j) a[d[j]]=j-L[i]+1;
for(int j=1;j<=R[i]-L[i]+1;++j) for(int k=1;k<j;++k)
if(p[k+L[i]-1]<p[j+L[i]-1]) ++b[i][j][a[j+L[i]-1]],++f[i][a[k+L[i]-1]][a[j+L[i]-1]];
for(int j=1;j<=R[i]-L[i]+1;++j)
for(int k=1;k<=R[i]-L[i]+1;++k) b[i][j][k]+=b[i][j][k-1],f[i][j][k]+=f[i][j][k-1];
for(int j=1;j<=R[i]-L[i]+1;++j) for(int k=1;k<=R[i]-L[i]+1;++k) b[i][j][k]+=b[i][j-1][k];
for(int j=R[i]-L[i];j;--j) for(int k=1;k<=R[i]-L[i]+1;++k) f[i][j][k]+=f[i][j+1][k];
}
for(int i=1;i<=n;++i){
++t[p[i]];
if(i==R[bl[i]]) for(int j=1;j<=n;++j) c[bl[i]][j]=c[bl[i]][j-1]+t[j];
}
for(int i=1;i<=bl[n];++i) for(int j=i+1;j<=bl[n];++j)
for(int k=1;k<=R[j]-L[j]+1;++k) e[i][j][k]=e[i][j][k-1]+c[i][p[d[k+L[j]-1]]];
for(int l,r,x,y;m--;printf("%lld\n",ans),ans=0){
scanf("%d%d%d%d",&l,&r,&x,&y);
if(bl[l]==bl[r]){ans=calc(l,r,x,y);continue;}
ans=calc(l,R[bl[l]],x,y)+calc(L[bl[r]],r,x,y);
for(int i=bl[l]+1;i<bl[r];++i)
ans+=e[i-1][i][rnk(i,y)]-e[bl[l]][i][rnk(i,y)]-e[i-1][i][rnk(i,x-1)]+e[bl[l]][i][rnk(i,x-1)],
ans-=(c[i-1][x-1]-c[bl[l]][x-1])*1ll*(rnk(i,y)-rnk(i,x-1)),ans+=f[i][rnk(i,x-1)+1][rnk(i,y)];
for(int i=l;i<=R[bl[l]];++i) if(p[i]>=x&&p[i]<=y)
ans+=c[bl[r]-1][y]-c[bl[l]][y]-c[bl[r]-1][p[i]]+c[bl[l]][p[i]];
for(int i=L[bl[r]];i<=r;++i) if(p[i]>=x&&p[i]<=y)
ans+=c[bl[r]-1][p[i]]-c[bl[l]][p[i]]-c[bl[r]-1][x-1]+c[bl[l]][x-1];
for(int i=L[bl[r]],j=L[bl[l]],cnt=0;i<=R[bl[r]];++i) if(p[d[i]]>=x&&p[d[i]]<=y&&d[i]<=r){
for(;j<=R[bl[l]]&&p[d[j]]<p[d[i]];++j) cnt+=(p[d[j]]>=x&&d[j]>=l);
ans+=cnt;
}
}
return 0;
}
//https://blog.csdn.net/chenshige/article/details/126274968