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

posted @ 2012-10-10 22:02  Griselda.  阅读(566)  评论(0)    收藏  举报