【HDU1394】Minimum Inversion Number(线段树)

大意:n次操作原串查询逆序数,求出所有串中最小的逆序数。

求逆序数属于线段树的统计问题,建立空树,每次进行插点时进行一次query操作即可。n次操作可以套用结论:如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],而增加n-1-a[i]。

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 const int maxn = 5e3 + 10;
 6 int sumv[maxn << 2];
 7 
 8 void PushUp (int rt) {
 9     sumv[rt] = sumv[rt * 2] + sumv[rt * 2 +1];
10 }
11 
12 void build (int l, int r, int rt) {
13     sumv[rt] = 0;
14     if (l == r) {
15         return ;
16     }
17     int m = (l + r) / 2;
18     build (l, m, rt * 2);
19     build (m + 1, r, rt * 2 + 1);
20 }
21 
22 void update (int p, int l, int r, int rt) {
23     if (l == r) {
24         sumv[rt] ++;
25         return ;
26     }
27     int m = (l + r) / 2;
28     if (p <= m) {
29         update (p, l, m, rt * 2);
30     }
31     if (p > m) {
32         update (p, m + 1, r, rt * 2 + 1);
33     }
34     PushUp (rt);
35 }
36 
37 int query (int L, int R, int l, int r, int rt) {
38     if (L <= l && r <= R) {
39         return sumv[rt];
40     }
41     int m = (l + r) / 2;
42     int ret = 0;
43     if (L <= m) {
44         ret += query (L, R, l, m, rt * 2);
45     }
46     if (R > m) {
47         ret += query (L, R, m + 1, r, rt * 2 + 1);
48     }
49     return ret;
50 }
51 
52 int x[maxn];
53 
54 int main () {
55     int n;
56     while (~scanf ("%d", &n)) {
57         build (0, n - 1, 1);
58         int sum = 0;
59         for (int i = 0 ; i < n; ++ i) {
60             scanf ("%d", &x[i]);
61             sum += query (x[i], n - 1, 0, n - 1, 1);
62             update (x[i], 0, n - 1, 1);
63         }
64         int res = sum;
65         for (int i =  0; i < n; ++ i) {
66             sum = sum + n - x[i] - 1 - x[i];
67             res = min (res, sum);
68         }
69         printf ("%d
", res);
70     }
71     return 0;
72 }
原文地址:https://www.cnblogs.com/Destiny-Gem/p/3877121.html