链接:http://poj.org/problem?id=2299
题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数。
分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起来就行了。逆序数可以用树状数组求。
n<500000,0<=a[i]<=999,999,999,很明显数组不可能开这么大,所以需要离散化。
可以用一个结构体
struct node{
int val,pos;
}a[N];
pos表示每个数的下标,val表示该数的值
按val从小到大排序,然后b[a[i].pos]]=i,就实现了离散化,保证了原来序列的大小关系不变。
之后就是简单的树状数组求逆序数了。
AC代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=500010; 6 #define LL __int64 7 int c[N],b[N],n; 8 struct node{ 9 int val,pos; 10 bool operator <(const node &a)const{ 11 return val<a.val; 12 } 13 }a[N]; 14 int lowbit(int x) 15 { 16 return x&(-x); 17 } 18 void update(int x,int num) 19 { 20 while(x<=N) 21 { 22 c[x]+=num; 23 x+=lowbit(x); 24 } 25 } 26 LL sum(int x) 27 { 28 LL s=0; 29 while(x>0) 30 { 31 s+=c[x]; 32 x-=lowbit(x); 33 } 34 return s; 35 } 36 int main() 37 { 38 int i; 39 while(scanf("%d",&n)&&n) 40 { 41 for(i=1;i<=n;i++) 42 { 43 scanf("%d",&a[i].val); 44 a[i].pos=i; 45 } 46 sort(a+1,a+n+1); 47 for(i=1;i<=n;i++) 48 b[a[i].pos]=i; 49 memset(c,0,sizeof(c)); 50 LL ans=0; 51 for(i=1;i<=n;i++) 52 { 53 update(b[i],1); 54 ans+=i-sum(b[i]); 55 } 56 printf("%I64d ",ans); 57 } 58 return 0; 59 }