POJ 2299 Ultra-QuickSort (树状数组 && 离散化&&逆序)

题意 : 给出一个数n(n<500,000), 再给出n个数的序列 a1、a2.....an每一个ai的范围是 0~999,999,999  要求出当通过相邻两项交换的方法进行升序排序时需要交换的次数

分析:其实经过一次模拟后,会发现奇妙的东西,这个排序都是按位置排的,最大要求到最大,最小要去到最小,转化思想这是一道求逆序对数的题目,答案就是逆序对数。

这里数据过大999999999,数组无法开的了这么大,我们可以离散化,只记录相对大小。

这里离散化有所不同,这里为了压时,用了空间换时间的方法. 前面的文章有讲到sum(i)表示前面有多少比这个小的数,可以sum(n)-sum(i), 这里有新知识就是sum(i)表示有多少小的数,那当前的总数是i,那大的数就是(i-sum(i)这也是求逆序对的方法,目测挺快的。

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int a[100];
int b[100],c[100],n;
int lowbit(int x)
{
    return x&(-x);
}
void add(int k,int num) {
    while(k<=n) {
        c[k]+=num;
        k+=lowbit(k);

    }
}
int sum(int k) {
    int ans=0;
    while(k) {
        ans+=c[k];
        k-=lowbit(k);

    }
    return ans;
}
int main( )
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(c,0,sizeof(c));
        if(n==0)
        break;
        for(int i=0 ; i<n ; i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b,b+n);
        int summ=0;

        for(int i=0 ; i<n ; i++)
        {
          a[i] = (lower_bound(b,b+n,a[i])-b)+1;
          summ+=(sum(n)-sum(a[i]));
          //summ+=(i-sum(a[i]+1)
          add(a[i],1);
        }
        printf("%d\n",summ);

    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/shuaihui520/p/9119706.html