【树状数组】 poj2299 Ultra-QuickSort

来源:互联网 发布:北京爱知科技有限公司 编辑:程序博客网 时间:2024/05/17 23:25

Ultra-QuickSort 

题目:http://poj.org/problem?id=2299

题意:给n个数字,每次只能交换相邻两个数字,问最少需要交换多少次可以将n个数字从小到大排序

题解:可以通过模拟冒泡排序发现,对于每个数字,要把它交换到排序后对应的位置,交换次数就等于它的逆序数,即题目等价于求逆序数。

逆序数定义:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数

代码:

#include<cstring>#include<cstdio>#include<algorithm>using namespace std;#define lowbit(x) ((x)&(-(x)))#define LL long longLL c[500005],b[500005];//c存和,b存逆序数int n;struct node{int value,num;}arr[500005];bool cmp(node x,node y){return x.value<y.value;}LL getsum(int pos){    int x=pos;    LL sum=0;    for(;x>0;x-=lowbit(x))        sum+=c[x];    return sum;}void update(int pos,int value) //更新pos的值{    int x=pos;    for(;x<=n;x+=lowbit(x))        c[x]+=value;}int main(){for(;scanf("%d",&n)&&n;){memset(c,0,sizeof(c));                for(int i=1;i<=n;i++){scanf("%d",&arr[i].value);arr[i].num=i;}sort(arr+1,arr+1+n,cmp);for(int i=1;i<=n;i++){arr[arr[i].num].value=i;//离散化}for(int i=1;i<=n;i++){update(arr[i].value,1);b[i]=i-getsum(arr[i].value);}__int64 ans=0;for(int i=1;i<=n;++i)ans+=b[i];printf("%I64d\n",ans);}return 0;}
来源:http://blog.csdn.net/ACM_Ted

原创粉丝点击