bzoj3289: Mato的文件管理

传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3289

思路:比较裸的莫队。

交换次数显然是逆序对个数...

然后考虑怎么从[l,r]的逆序对个数得到[l,r+1]的逆序对个数。

先离散化,用树状数组维护权值,我们只要考虑对于新加进来的这个数,原区间中有多少个数大于它,拿区间长度去减就可以得到这个数的贡献。

删除一个数类似。

复杂度O(n^1.5*logn)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=50010;
using namespace std;
struct data{int id,rank;}file[maxn];
struct que{int l,r,id;}q[maxn];
int n,m,sz,a[maxn],bel[maxn],ans[maxn],cnt,res,T[maxn];
bool cmp(data a,data b){return a.rank<b.rank;}
bool cmp2(que a,que b){return bel[a.l]==bel[b.l]?a.r<b.r:bel[a.l]<bel[b.l];}
void modify(int x,int add){for (;x<=n;x+=x&(-x)) T[x]+=add;}
int query(int x){int res=0;for (;x;x-=x&(-x)) res+=T[x];return res;}

void work(){
	for (int i=1,l=1,r=0;i<=m;i++){
		for (;r<q[i].r;r++) res+=(r-l+1-query(a[r+1])),modify(a[r+1],1);
		for (;r>q[i].r;r--) res-=(r-l+1-query(a[r])),modify(a[r],-1);
		for (;l<q[i].l;l++) res-=query(a[l]-1),modify(a[l],-1);
		for (;l>q[i].l;l--) res+=query(a[l-1]-1),modify(a[l-1],1);
		ans[q[i].id]=res;
	}
	for (int i=1;i<=m;i++) printf("%d
",ans[i]);
}

int main(){
	scanf("%d",&n);sz=sqrt(n);
	for (int i=1;i<=n;i++) bel[i]=(i-1)/sz+1;
	for (int i=1;i<=n;i++) scanf("%d",&file[i].rank),file[i].id=i;
	sort(file+1,file+1+n,cmp);
	for (int i=1;i<=n;i++){if (file[i].rank!=file[i-1].rank) ++cnt;a[file[i].id]=cnt;}
	scanf("%d",&m);
	for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
	sort(q+1,q+1+m,cmp2),work();
	return 0;
}


原文地址:https://www.cnblogs.com/thythy/p/5493541.html