线段树的一个应用,求逆序数。思路为:sum[i]为0代表i未出现,为1则已经出现,
然后查询时我们只要统计新加入的数到n-1这个范围内有多少个sum[i]为1,也就是当前
数的逆序,然后累加,就是我们要求的逆序数。因为其他形式都可以由第一次求得的逆
序数递推而来,所以只需计算一次。
/*2012-08-07 16:54:38 Accepted 1394 78MS 252K 1478 B G++ Yu*/ #include<stdio.h> #include<algorithm> using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 const int MAXN = 5050; int sum[MAXN << 2]; int n, x[MAXN]; void PushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void build(int l, int r, int rt) { int m = l + r >> 1; sum[rt] = 0; if(l == r) return; build(lson); build(rson); PushUp(rt); } void update(int p, int l, int r, int rt) { int m = l + r >> 1; if(l == r) { sum[rt] ++; return; } if(p <= m) update(p, lson); else update(p, rson); PushUp(rt); } int query(int L, int R, int l, int r, int rt) { int m = l + r >> 1, ret = 0; if(L <= l && r <= R) { return sum[rt]; } if(L <= m) ret += query(L, R, lson); if(R > m) ret += query(L, R, rson); return ret; } int main() { int i, ans, ret; while(scanf("%d", &n) == 1) { build(0, n - 1, 1); ans = 0; for(i = 0; i < n; i ++) { scanf("%d", &x[i]); ans += query(x[i], n - 1, 0, n - 1, 1); //查询在x[i]之前比它大的数的个数,累加。 update(x[i], 0, n - 1, 1); } ret = 0x3f3f3f3f; for(i = 0; i < n; i ++) { ans += n - x[i] - x[i] - 1; ret = min(ret, ans); } printf("%d\n", ret); } return 0; }
浙公网安备 33010602011771号