POJ 2299 Ultra-QuickSort 树状数组+离散化 求逆序对

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

 

解题思路:

树状数组的参考资料:https://www.cnblogs.com/hsd-/p/6139376.html

这里就不再赘述了。

基本思路是将一组数据从大到小插入,然后累加每次插入时计算前面比它大的元素个数(即构成逆序),这里利用离散化+树状数组,每次插入时计算插入位置n之前的n-1项和即可

输入数据同时记录下对应的数组下标,方便排序后将数据从大到小插入1。注意这里的“原数组”a[i]是不存在的,直接更新a[i]对应的树状数组即可

以9 1 0 5 4 为例,插入1的数序是 9 5 4 1 0 的对应位置

a[ ]起始为 0 0 0 0 0

插入9后 1 0 0 0 0  ans +=  0

插入5后 1 0 0 1 0   ans += 1

插入4后 1 0 0 1 1   ans += 2 

插入1后 1 1 0 1 1   ans += 1

插入0后 1 1 1 1 1   ans += 2

最后输出6

 

代码如下

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 500010;

struct T{
    int d; // data
    int id; //index
    bool operator < (const T& t) const{ //使原始数据按降序排序
        return d > t.d;
    }
} b[maxn];

int n;
int c[maxn]; //树状数组
int lowbit(int x)
{
    return x&(-x);
}

void add(int x,int y)  //update c
{
    for(int i = x; i <=n; i+=lowbit(i))
    {
        c[i] += y;
    }
}

int getSum(int x)  // get sum of a[1..x],求a数组的前x项和 
{
    int sum = 0;
    for(int i = x; i >0; i -= lowbit(i))
        sum += c[i];
    return sum;
}

int main()
{
    
    long long ans; // int型会溢出
    while(cin >> n && n)
    {
        memset(c,0,sizeof(c));
        ans = 0;
        for(int i = 1; i <= n; ++i)
        {
            cin >> b[i].d;
            b[i].id = i;
        }
        sort(b+1,b+n+1);
        for(int i = 1; i <= n; ++i)
        {
            int id = b[i].id;
            add(id,1); //注意这里省略了插入1到a数组的过程(因为用不上),直接更新c数组(树状数组)
            ans += getSum(id-1);
        }
        cout << ans << endl;
    }
    return 0;
}

 

posted @ 2018-03-28 00:25  SeanLiao  阅读(138)  评论(0编辑  收藏  举报