Hdu 1394 【线段树 基础 求逆序数】.cpp

题意:

  给出n个数..问循环排序后的最小逆序数

 

思路:

  根据出现次序..用线段树的sum记录某一区间出现次数..

     把出现的数值a[i] 更新到 sum[a[i]]..

     根据题意..当每一次更新的之前..都对当前位置到最后位置出现的数进行查询..

  即可得到出现比该值早而又比该值大的数的个数..即满足逆序数对的定义..

     所以求和就可得到逆序数对的值..

 

   当每一次把队头的值移到队尾..

  逆序数对就减少了当前值(a[i]-1)<逆序数对包含该值的都没有了..>..

     但是还有一些逆序数对增加了..(加入到队尾时可与该数组成逆序数对的..)即n-a[i]对..

     所以每一次循环后存在的逆序数对个数就是:sum = sum-(a[i]-1) + (n-a[i]);

Tips:

    暴力超时了..所以用线段树来算..

 

Code:

View Code
  1 #include <stdio.h>

  2 #include <cstring>

  3 #include <algorithm>

  4 using namespace std;

  5 

  6 const int MAXN = 5010;

  7 int sum[MAXN<<2];

  8 int a[MAXN];

  9 

 10 void pushup(int rt)

 11 {

 12     sum[rt] = sum[rt<<1] + sum[rt<<1|1];

 13 }

 14 

 15 void creat(int l, int r, int rt)

 16 {

 17     sum[rt] = 0;

 18     if(l == r)

 19         return;

 20     int mid = (l+r)>>1;

 21     creat(l, mid, rt<<1);

 22     creat(mid+1, r, rt<<1|1);

 23     pushup(rt);

 24 }

 25 

 26 void modify(int p,int l, int r, int rt)

 27 {

 28     if(l == r) {

 29         sum[rt]++;

 30         return;

 31     }

 32     int mid = (l+r)>>1;

 33     if(p <= mid) modify(p, l, mid, rt<<1);

 34     else modify(p, mid+1, r, rt<<1|1);

 35     pushup(rt);

 36 }

 37 

 38 int query(int l, int r, int L, int R, int rt)

 39 {

 40     if(l <= L && R <= r) {

 41         return sum[rt];

 42     }

 43     int mid = (L+R)>>1;

 44     int res = 0;

 45     if(l <= mid) res += query(l, r, L, mid, rt<<1);

 46     if(r > mid) res += query(l, r, mid+1, R, rt<<1|1);

 47     return res;

 48 }

 49 

 50 int main()

 51 {

 52     int i, j, k;

 53     int n, sum;

 54     while(scanf("%d", &n) != EOF)

 55     {

 56         int s = 0;

 57         creat(1, n, 1);

 58 

 59         for(i = 0; i < n; ++i) {

 60             scanf("%d", &a[i]);

 61             a[i]++;

 62             s += query(a[i], n, 1, n, 1);

 63             modify(a[i], 1, n, 1);

 64         }

 65 

 66         int mi = 0x1f1f1f1f;///!!!

 67         for(i = 0; i < n; ++i) {

 68             s = s-(a[i] - 1)+(n-a[i]);

 69             mi = min(mi, s);

 70         }

 71 

 72         printf("%d\n", mi);

 73     }

 74     return 0;

 75 }

 76 

 77 /*

 78 int main()

 79 {

 80     int i, j, k;

 81     int n;

 82     while(scanf("%d", &n) != EOF)

 83     {

 84         for(i = 0; i < n; ++i) {

 85             scanf("%d", &a[i]);

 86         }

 87 

 88         int mi = 0x1f1f1f1f, s = 0;

 89         for(i = 0; i < n; ++i) {

 90             creat(1, n, 1);

 91             s = 0;

 92             for(j = 0; j < n; ++j) {

 93                 s += query(a[(i+j)%n]+1, n, 1, n, 1);

 94                 modify(a[(j+i)%n]+1, 1, n, 1);

 95             }

 96             mi = min(mi, s);

 97         }

 98 

 99         printf("%d\n", mi);

100     }

101     return 0;

102 }

103 */

 

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

你可能感兴趣的:(HDU)