POJ 2299 Ultra-QuickSort (树状数组+离散化)

题目描述:给出一个序列,求出这个序列的逆序数。

逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。一个排列中所有逆序总数叫做这个排列的逆序数。也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

例如  序列 9 1 0 5 4 的逆序数为6

         序列 1 2 3 4 5 的逆序数为0

树状数组解题思路:开一个能大小为这些数的最大值的树状数组,并全部置0。从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是总的逆序对数。

离散化:本题数字最大为999999999,如果直接开数组那会浪费大量空间,又由于本题的序列长度不超过500000,所以经过离散化之后开长度为500000的数组就行了。

例如  序列 9 1 0 5 4 离散化后为 5 2 1 4 3

         序列 5 6 8 1 0 离散化后为 3 4 5 2 1

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))

using namespace std;

const int maxn = 5e5 + 5 , inf = 0x3f3f3f3f ;
int A[maxn],C[maxn];
int n,t;
struct number{
    int value,pos;
    bool operator < (const number & n ) const {
        return value < n.value;
    }
};
number numbers[maxn];
int lowbit(int x){return x&(-x);}
void Updata(int x){
    for(int i = x ; i <= n ; i += lowbit(i))
        C[i] += 1;
}
int getSum(int x){
    int ans = 0;
    for(int i = x ; i > 0 ; i -= lowbit(i))
        ans += C[i];
    return ans;
}
int main(){
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    while(scanf("%d",&n)&&n){
        mem(A);mem(C);mem(numbers);
        
        //离散化
        for(int i = 1 ; i <= n ; i ++ ){
            scanf("%d",&numbers[i].value);
            numbers[i].pos = i;
        }
        sort(numbers+1,numbers+n+1);
        for(int i = 1 ; i <= n ; i ++ ){
            A[numbers[i].pos] = i;
        }
        
        //ans要定义为long long
        ll ans = 0;
        for(int i = 1 ; i <= n ; i ++ ){
            Updata(A[i]);
            ans += i - getSum(A[i]);
        }
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(树状数组)