zoukankan      html  css  js  c++  java
  • hdu1394 Minimum Inversion Number ——线段树入门题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394

    题目大意:

      给一个数字由0~n-1这n个数字组成的数列,不断地把第一个数字移动到最后,一共得到n个数列。求这n个数列中,逆序数最小是多少。

    题目思路:

      首先,建一棵线段树,每个节点表示这个区间内已经插入的数字的个数,开始初始化为0.然后没读入一个数字,把这个数字插入得到线段树的叶子节点,然后向上更新父节点。这样,在建树的过程中,就可以统计出每个逆序数,也就是说,可以再插入每个数字的时候,查找已经插入的数字当中,比这个数字大的数字有多少个,直到最后就可以求出这个数列的逆序数。

      然后,利用数列的性质。因为每次都是把第一个数字移动到最后,比如这个数字是a,那么显然,比这个数字小的有a个,比这个数字大的有n-1-a个;因为这个数字在最前面,所以当前这个数字的逆序数是a,把这个数字移动到最后之后,这个数字的逆序数是n-1-a,逆序数增加量:n-1-a-a。这样就可以由原来的数列的逆序数求出所有数列的逆序数。好神奇~

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cctype>
     6 #include <stack>
     7 #include <queue>
     8 #include <map>
     9 #include <set>
    10 #include <vector>
    11 #include <cmath>
    12 #include <algorithm>
    13 #define lson l, m, rt<<1
    14 #define rson m+1, r, rt<<1|1
    15 using namespace std;
    16 typedef long long int LL;
    17 const int MAXN =  0x3f3f3f3f;
    18 const int  MIN =  -0x3f3f3f3f;
    19 const double eps = 1e-9;
    20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
    21   {1,1},{1,-1},{-1,-1}};
    22 const int MAX = 5000+10;
    23 int a[MAX<<2], n, b[MAX];
    24 void pushup(int rt)
    25 {
    26   a[rt] = a[rt<<1] + a[rt<<1|1];
    27 }
    28 void build(int l, int r, int rt)
    29 {
    30   if (l == r) { a[rt] = 0; return; }
    31   int m = (l + r) >> 1;
    32   build(lson); build(rson); pushup(rt);
    33 }
    34 void update(int p, int l, int r, int rt)
    35 {
    36   if (l == r) { a[rt]++; return; }
    37   int m = (l + r) >> 1;
    38   if (p <= m) update(p, lson);
    39   else update(p, rson);
    40   pushup(rt);
    41 }
    42 int query(int L, int R, int l, int r, int rt)
    43 {
    44   if (L <= l && R >= r) { return a[rt]; }
    45   int m = (l + r) >> 1, ret = 0;
    46   if (L <= m) ret += query(L, R, lson);
    47   if (R > m) ret += query(L, R, rson);
    48   return ret;
    49 }
    50 int main(void){
    51 #ifndef ONLINE_JUDGE
    52   freopen("hdu1394.in", "r", stdin);
    53 #endif
    54   while (~scanf("%d", &n)){
    55     int i, j, sum; build(0, n - 1, 1);
    56     sum = 0;
    57     for (i = 0; i < n; ++i){
    58       scanf("%d", b + i);
    59       sum += query(b[i]+1, n - 1, 0, n - 1, 1);
    60       update(b[i], 0, n - 1, 1);
    61     }
    62     int ans = sum;
    63     for (i = 0; i < n; ++i){
    64       sum += (n - 1 - b[i] * 2);
    65       ans = min(ans, sum);
    66     }
    67     printf("%d\n", ans);
    68   }
    69 
    70   return 0;
    71 }

      现在写点更新的线段树比以前熟练一点了~接下来练区间更新的。

  • 相关阅读:
    bzoj 4911: [Sdoi2017]切树游戏
    bzoj 2654: tree
    bzoj 3240: [Noi2013]矩阵游戏
    有标号的DAG计数 III
    有标号的DAG计数 II
    bzoj 3512: DZY Loves Math IV
    bzoj 4480: [Jsoi2013]快乐的jyy
    bzoj 5323: [Jxoi2018]游戏
    codeforces412A
    7.6 T1 深度优先搜索(dfs)
  • 原文地址:https://www.cnblogs.com/liuxueyang/p/3039247.html
Copyright © 2011-2022 走看看