在数组a中a[i],a[j]是一个逆序对,当且仅当i<j且a[i]>a[j]时成立。
先考虑下暴力求法:
求以a[i]为大数的逆序对的个数,则我们检索0~i-1中大于a[i]的个数记入总数。
时间复杂度:n^2,复杂度很高。
现在我们考虑下,利用线段树的方法。
我们每拿到一个数我们就必须求出前面比这个数大的数的个数 k,于是我们可以用线段树记下区间数的个数,查询出这k就可以了,每次我们求完一个数的逆序对数就把这数放入线段树并经行维护。
当数非常大时,我们可以离散化下就可以了,以下代码是带有离散处理的。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define model l,mid,num<<1
#define moder mid+1,r,num<<1|1
using namespace std;
typedef long long LL;
int MAX;
const int M=1e5+5;
struct node{
LL v;//记下数值。
int x;//记下下标。
node(){};
node(LL vv,int xx){v=vv,x=xx;};
};
node record[M];
LL arr[M];
int n;
void poshash()
{
sort(record+1,record+n+1,[](node a,node b){return a.v<b.v;});
MAX=1;
for(int i=1;i<=n;++i)
{
if(record[i].v!=record[i-1].v&&i!=1)MAX++;
arr[record[i].x]=MAX;
}
return ;
}
int pre[M<<2];
int query(int L,int R,int l,int r,int num)
{
if(L>R)return 0;
if(L<=l&&r<=R)
{
return pre[num];
}
int mid=(l+r)/2;
if(R<=mid)return query(L,R,model);
else if(mid<L)return query(L,R,moder);
else if(L<=mid&&mid<R)return query(L,R,model)+query(L,R,moder);
}
void update(int L,int R,int key,int l,int r,int num)
{
if(L<=l&&r<=R)
{
pre[num]+=key;
return ;
}
int mid=(l+r)/2;
if(mid<L)update(L,R,key,moder);
else if(R<=mid)update(L,R,key,model);
else if(L<=mid&&mid<R)
{
update(L,R,key,model);
update(L,R,key,moder);
}
pre[num]=pre[num<<1]+pre[num<<1|1];
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;++i)
{
scanf("%d",&arr[i]);
record[i]=node(arr[i],i);
}
poshash();
memset(pre,0,sizeof(pre));
int sum=0;
for(int i=1;i<=n;++i)
{
sum+=query(arr[i]+1,MAX,1,MAX,1);
update(arr[i],arr[i],1,1,MAX,1);
}
cout<<sum<<endl;
}
}