[BZOJ3744]Gty的妹子序列

bzoj

description

求区间逆序对数,强制在线。
\(n,m\le 10^5\)

sol

分块。预处理出\(ans_{i,j}\)表示第\(i\)个块到第\(j\)个块的答案,\(s_i\)表示插入了前\(i\)个块内所有元素的\(BIT\)
每次查询的时候开一个临时\(BIT\),对于整块两端的部分,先从右往左加入左边部分(这时候统一计算比自己小的个数),再从左往右加入右边部分(统一计算比自己大的个数)。
时间复杂度\(O(n\sqrt n\log n)\),空间复杂度\(O(n\sqrt n)\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 5e4+5;
const int M = 250;
int n,m,block,q,a[N],o[N],len,pos[N],L[M],R[M],ans[M][M],s[M][N],tmp[N],Ans;
void add(int k,int v,int *c){
	for (int i=k;i<=len;i+=i&-i) c[i]+=v;
}
int sum(int k,int *c){
	int res=0;
	for (int i=k;i;i-=i&-i) res+=c[i];
	return res;
}
void init(){
	block=sqrt(n);m=(n-1)/block+1;
	for (int i=1;i<=n;++i) pos[i]=(i-1)/block+1;
	for (int i=1;i<=m;++i) L[i]=(i-1)*block+1,R[i]=i*block;
	R[m]=n;
	for (int i=1;i<=m;++i){
		int res=0;
		for (int j=L[i];j<=n;++j){
			res+=sum(len,tmp)-sum(a[j],tmp),add(a[j],1,tmp);
			if (j==R[pos[j]]) ans[i][pos[j]]=res;
		}
		memset(tmp,0,sizeof(tmp));
	}
	for (int i=1;i<=m;++i){
		memcpy(s[i],s[i-1],sizeof(s[i]));
		for (int j=L[i];j<=R[i];++j)
			add(a[j],1,s[i]);
	}
}
int query(int l,int r){
	int res=0;
	if (pos[r]-pos[l]<=1){
		for (int i=l;i<=r;++i)
			res+=sum(len,tmp)-sum(a[i],tmp),add(a[i],1,tmp);
		for (int i=l;i<=r;++i) add(a[i],-1,tmp);
		return res;
	}else{
		res=ans[pos[l]+1][pos[r]-1];
		for (int i=R[pos[l]];i>=l;--i){
			res+=sum(a[i]-1,s[pos[r]-1]);
			res-=sum(a[i]-1,s[pos[l]]);
			res+=sum(a[i]-1,tmp);
			add(a[i],1,tmp);
		}
		for (int i=L[pos[r]];i<=r;++i){
			res+=sum(len,s[pos[r]-1])-sum(a[i],s[pos[r]-1]);
			res-=sum(len,s[pos[l]])-sum(a[i],s[pos[l]]);
			res+=sum(len,tmp)-sum(a[i],tmp);
			add(a[i],1,tmp);
		}
		for (int i=R[pos[l]];i>=l;--i) add(a[i],-1,tmp);
		for (int i=L[pos[r]];i<=r;++i) add(a[i],-1,tmp);
		return res;
	}
}
int main(){
	n=gi();
	for (int i=1;i<=n;++i) a[i]=o[i]=gi();
	sort(o+1,o+n+1);len=unique(o+1,o+n+1)-o-1;
	for (int i=1;i<=n;++i) a[i]=lower_bound(o+1,o+len+1,a[i])-o;
	init();q=gi();while (q--){
		int l=gi()^Ans,r=gi()^Ans;
		printf("%d\n",Ans=query(l,r));
	}
	return 0;
}
posted @ 2018-06-27 22:05  租酥雨  阅读(198)  评论(0编辑  收藏  举报