时代的眼泪我的代码各个变量的含义

设询问的下标区间 [ 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](1in)表示第 i i i个位置属于第几个块
L [ i ] ( 1 ≤ i ≤ n ) L[i](1\leq i\leq n) L[i](1in)表示第 i i i块最靠左的是哪个位置
R [ i ] ( 1 ≤ i ≤ n ) R[i](1\leq i\leq n) R[i](1in)表示第 i i i块最靠右的是哪个位置
a [ i ] ( 1 ≤ i ≤ n ) a[i](1\leq i\leq n) a[i](1in)表示第 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](0iBn,0jB,0kB)表示仅考虑第 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](0iBn,0jn)表示前 i i i块小于等于 j j j的数有多少个
d [ i ] ( 1 ≤ i ≤ n ) d[i](1\leq i\leq n) d[i](1in)表示把每一块块内排序后现在第 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](0iBn,i<jBn,0kB)表示第一个位置位于前 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](1iBn,0jB,jkB)表示第 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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值