BZOJ 3744: Gty的妹子序列(分块+树状数组)

传送门

解题思路

  首先分块预处理,设\(sum[i][j]\)为第\(i\)块到第\(j\)块的逆序对数量,\(g[i][j]\)表示前\(i\)块数值\(<=j\)的数量,这两个东西是可以\(O(n\sqrt(n)log(n))\)预处理出来的。询问的时候大块直接查询\(sum\),边角元素之间的贡献直接树状数组,边角元素与大块之间的贡献变成前缀和用\(g\)数组,时间复杂度\(O(n\sqrt(n)log(n))\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=50005;
const int M=300;

inline int rd(){
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;	
}

int n,a[N],cpy[N],lstans,u,num,m,b[N];
int sum[M][M],siz,bl[N],l[M],r[M],g[M][N];

struct BIT{
	int f[N];
	inline void clear(){
		memset(f,0,sizeof(f));	
	}
	inline void add(int x,int k){
		for(;x<=u;x+=x&-x) f[x]+=k;	
	}
	inline int query(int x){
		int ret=0;
		for(;x;x-=x&-x) ret+=f[x];
		return ret;	
	}
}tree;

inline void prework(){
	for(int i=1;i<=n;i++) g[bl[i]][a[i]]++;
	for(int i=1;i<=num;i++) 
		for(int j=1;j<=u;j++)
			g[i][j]+=g[i][j-1];
	for(int i=2;i<=num;i++)
		for(int j=1;j<=u;j++)
			g[i][j]+=g[i-1][j];
	for(int i=1;i<=num;i++){
		tree.clear();
		for(int j=l[i];j<=n;j++){
			sum[i][bl[j]]+=tree.query(u)-tree.query(a[j]);
			tree.add(a[j],1);
		}
	}
	for(int i=1;i<=num;i++)
		for(int j=i+1;j<=num;j++)
			sum[i][j]+=sum[i][j-1];
}	

inline int query(int x,int y){
	tree.clear(); int ret=0;
	if(bl[x]==bl[y]){
		for(int i=x;i<=y;i++){
			ret+=tree.query(u)-tree.query(a[i]);
			tree.add(a[i],1);	
		}
		return ret;
	}
	ret=sum[bl[x]+1][bl[y]-1];
	for(int i=x;i<=r[bl[x]];i++){
		ret+=tree.query(u)-tree.query(a[i]);
		if(bl[y]-1>bl[x]);
		ret+=g[bl[y]-1][a[i]-1]-g[bl[x]][a[i]-1];
		tree.add(a[i],1);
	}
	for(int i=l[bl[y]];i<=y;i++){
		ret+=tree.query(u)-tree.query(a[i]);
		if(bl[y]-1>bl[x]);
		ret+=(g[bl[y]-1][u]-g[bl[x]][u])-(g[bl[y]-1][a[i]]-g[bl[x]][a[i]]);
		tree.add(a[i],1);	
	}
	return ret;
}

int main(){
	n=rd(); siz=sqrt(n)+1; num=n/siz; if(n%siz) num++;
	for(int i=1;i<=n;i++) cpy[i]=a[i]=rd(),bl[i]=(i-1)/siz+1;
	for(int i=1;i<=num;i++) l[i]=(i-1)*siz+1,r[i]=i*siz;
	sort(cpy+1,cpy+1+n); u=unique(cpy+1,cpy+1+n)-cpy-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(cpy+1,cpy+1+u,a[i])-cpy;
	for(int i=1;i<=n;i++) b[i]=a[i]; 
	r[num]=n; prework(); m=rd(); int l,r;
	while(m--){
		l=rd(),r=rd(); l^=lstans; r^=lstans;
		lstans=query(l,r); printf("%d\n",lstans);
	}
	return 0;	
}
posted @ 2019-02-12 19:55  Monster_Qi  阅读(172)  评论(0编辑  收藏  举报