【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3289
【题意】
回答若干个询问:[l,r]区间内的逆序对个数。
【思路】
莫队算法,BIT维护插入删除。
使用BIT维护当前指针l,r内的所有的数。考虑转移部分:
l<q[i].l 删出区间中比a[l]小的数与之构成的逆序对,Q(a[l]-1)
l>q[i].l l++,添加区间中比a[l]小的数与之构成的逆序对,Q(a[l]-1)
r>q[i].r 删除区间中比a[r]大的数与之构成的逆序对,r-l+1-Q(a[r])
r<q[i].r r++,添加区间中比a[r]大的数与之构成的逆序对,r-l-Q(a[r])
相应修改BIT。
这一部分比较容易出错 =_=
【代码】
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
using namespace std; typedef long long ll;
const int N = 1e5+; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Node {
int pos,id,l,r;
bool operator < (const Node& rhs) const
{
return pos<rhs.pos||(pos==rhs.pos&&r<rhs.r);
}
} q[N]; int n,m;
int C[N],a[N],hash[N],tot;
ll ans[N]; void add(int x,int v)
{
for(;x<=tot;x+=x&-x) C[x]+=v;
}
ll query(int x)
{
ll sum=;
for(;x;x-=x&-x) sum+=(ll)C[x];
return sum;
} int main()
{
n=read();
FOR(i,,n) a[i]=read(),hash[++tot]=a[i];
sort(hash+,hash+n+);
tot=unique(hash+,hash+n+)-hash-;
FOR(i,,n) a[i]=lower_bound(hash+,hash+n+,a[i])-hash; m=read();
int B=sqrt(n);
FOR(i,,m)
{
q[i].l=read(),
q[i].r=read();
q[i].id=i;
q[i].pos=(q[i].l-)/B+;
}
sort(q+,q+m+); ll now=;
int l=,r=;
FOR(i,,m)
{
while(l<q[i].l)
now-=query(a[l]-),add(a[l],-),l++;
while(l>q[i].l)
l--,now+=query(a[l]-),add(a[l],);
while(r>q[i].r)
now-=r-l+-query(a[r]),add(a[r],-),r--;
while(r<q[i].r)
r++,now+=r-l-query(a[r]),add(a[r],);
ans[q[i].id]=now;
} FOR(i,,m)
printf("%lld\n",ans[i]);
return ;
}