【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\n", res);

70     }

71     return 0;

72 }

 

你可能感兴趣的:(version)