Time:2016.09.07
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
这个题意就是让你求[l,r]的逆序对数
暴力做的话是
O(Qn2)
或
O(Qnlogn)
考虑莫队做法
那怎么在莫队转移的时候快速计算逆序对数呢?
如果我们当前的区间是[l,r]
转移[l+1,r]—>减去的答案就是[l,r]中比a[l]小的数的个数
转移[l-1,r]—>加上的答案就是[l,r]中比a[l-1]小的数的个数
转移[l,r+1]—>加上的答案就是[l,r]中比a[r+1]大的数的个数
转移[l,r-1]—>减去的答案就是[l,r]中比a[r]大的数的个数
这个东西我们可以用离散化+树状数组来搞啊
这样的话复杂度就是
O(nn√logn)
比较玄学的复杂度
注意离散化后树状数组的区间并不是[1,n]
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define low(x) (x&-x)
#define M 50003
using namespace std;
int n,m;
int a[M],b[M],c[M],d[M],block[M];
struct query{
int l,r,id;
}q[M];
bool cmp(query a,query b)
{
if (block[a.l]==block[b.l]) return a.r<b.r;
return block[a.l]<block[b.l];
}
int in()
{
int t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void add(int x,int val)
{
for (;x<=b[0];x+=low(x))
d[x]+=val;
}
int get(int x)
{
int ans=0;
for (;x;x-=low(x))
ans+=d[x];
return ans;
}
main()
{
n=in();
int t=sqrt(n);
for (int i=1;i<=n;++i)
a[i]=b[i]=in(),
block[i]=i/t+1;
sort(b+1,b+n+1);
b[0]=unique(b+1,b+n+1)-b-1;
for (int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b;
m=in();
for (int i=1;i<=m;++i) q[i]=(query){in(),in(),i};
sort(q+1,q+m+1,cmp);
int L=1,R=0,ans=0;
for (int i=1;i<=m;++i)
{
for (int j=R+1;j<=q[i].r;++j)
ans+=get(b[0])-get(a[j]),
add(a[j],1);
for (int j=R;j>q[i].r;--j)
ans-=get(b[0])-get(a[j]),
add(a[j],-1);
for (int j=L;j<q[i].l;++j)
ans-=get(a[j]-1),
add(a[j],-1);
for (int j=L-1;j>=q[i].l;--j)
ans+=get(a[j]-1),
add(a[j],1);
L=q[i].l;R=q[i].r;
c[q[i].id]=ans;
}
for (int i=1;i<=m;++i) printf("%d\n",c[i]);
}