题目链接:http://poj.org/problem?id=2299
题意:大概就是冒泡排序中一共交换了多少次;
离散化:c[]数组用二进制开不了999999999的空间,所以把a[]数组中对应的值给变小作用效果不变
用结构体 pos表示离散后的值得下标,val表示原来值;
struct node{
int pos,val;
bool operator < (const node&b)const{
return val<b.val;
}
}p[maxn];
例:9 1 0 5 4 总共要变化6次,离散后变成 5 2 1 4 3也是6次;数值变小作用相同,
在具体用的时候要先对p[]中按val由小到大排序,保证p[].val值和(1,2,3....n)(即下标)大小变化对应。再把离散后的值给a[]
for(int i=1;i<=n;i++){
scanf("%d",&p[i].val);
p[i].pos = i;
}
sort(p+1,p+n+1);
ll ans=0;
for(int i=1;i<=n;i++)
a[p[i].pos]=i;
即:a[3]=1,a[2]=2,a[5]=3,a[4]=4,a[1]=5;
之后进行树状数组找逆序数:
每插入一个数, 统计比他小的数的个数,
对应的逆序为 i- sum( a[i] ),
其中 i 为当前已经插入的数的个数,
sum( a[i] )为比 a[i] 小的数的个数,
i- sum( a[i] ) 即比 a[i] 大的个数, 即逆序的个数
因为getsum()是自顶向下的,下面的肯定是比他小,而我们找的是在输入的个数中比他大的个数(这样的话就会形成逆序),就是i- sum( a[i] ) ;
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 510000;
struct node{
int pos,val;
bool operator < (const node&b)const{
return val<b.val;
}
}p[maxn];
int a[maxn],c[maxn];
int n;
int lowbit(int x){
return x&(-x);
}
int getsum(int x){
int s=0;
for(int i=x;i;i-=lowbit(i))
s+=c[i];
return s;
}
void updata(int x,int k){
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=k;
}
int main(){
while(~scanf("%d",&n)&&n){
memset(c,0,sizeof c);
for(int i=1;i<=n;i++){
scanf("%d",&p[i].val);
p[i].pos = i;
}
sort(p+1,p+n+1);
ll ans=0;
for(int i=1;i<=n;i++)
a[p[i].pos]=i;
for(int i=1;i<=n;i++){
updata(a[i],1);
ans+=(i-getsum(a[i]));
}
printf("%lld\n",ans);
}
return 0;
}