现在的位置: 首页 > 算法 > 正文

poj – 2299 – Ultra-QuickSort(树状数组)

2019年08月29日 算法 ⁄ 共 1017字 ⁄ 字号 评论关闭

题意:求长度为n(n < 500000),元素范围为[0, 999999999]的数组的逆序对数。

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

——>>设x[i]表示数i已经出现的次数,从后往前扫描,对于每个数k,那么k产生的逆序对数为x[0] + x[1] + ... + x[k-1],于是可以用树状数组了。

——>>由于元素范围可到999999999,所以应做离散化操作。

——>>如果所有数逆序出现,那么逆序对数最多为n(n-1)/2,代入n = 500000可知已超32位整数范围,应用64位整数。

第一次用了STL的unique和resize还有map,TLE了。。。第二次,全改了。。。T_T。。。

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 500000 + 10;

int n;
long long c[maxn];

typedef struct CNode {
    int id;
    int v;
    bool operator < (const CNode& e) const {
        return v < e.v || (v == e.v && id < e.id);
    }
} Node;

Node a[maxn];
int p[maxn];

int lowerbit(int x) {
    return x & (-x);
}

long long sum(int x) {
    long long ret = 0;
    while(x > 0) {
        ret += c[x];
        x -= lowerbit(x);
    }
    return ret;
}

void add(int x) {
    while(x <= n) {
        c[x]++;
        x += lowerbit(x);
    }
}

int main()
{
    while(scanf("%d", &n) == 1 && n) {
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i].v);
            a[i].id = i;
        }

        sort(a, a+n);
        int stamp = 1;
        p[a[0].id] = stamp;
        for(int i = 1; i < n; i++) {
            if(a[i].v > a[i-1].v) stamp++;
            p[a[i].id] = stamp;
        }
        memset(c, 0, sizeof(c));
        long long ret = 0;
        for(int i = n-1; i >= 0; i--) {
            ret += sum(p[i]-1);
            add(p[i]);
        }
        printf("%I64d\n", ret);
    }
    return 0;
}

抱歉!评论已关闭.