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