题意:求长度为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;
}