码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 1394 求一个序列的最小逆序数 单点增 区间求和

时间:2015-06-26 21:02:43      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:

题目的意思就好比给出一个序列

如:0 3 4 1 2

设逆序数初始n = 0;

由于0后面没有比它小的,n = 0

3后面有1,2 n = 2

4后面有1,2,n = 2+2 = 4;

所以该序列逆序数为 4

或者这样想

先输0 前面没有比它大的 n = 0
3也没有 4也没有
1前面 3 4 比它大 n += 2
2前面 3 4 比它大 n += 2
n = 4

其根据题意移动产生的序列有

3 4 1 2 0 逆序数:8

4 1 2 0 3 逆序数:6

1 2 0 3 4 逆序数:2

2 0 3 4 1 逆序数:4

所以最小逆序数为2

 

Sample Input
10
1 3 6 9 0 8 5 7 4 2

Sample Output
16

 

技术分享
 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 # include <algorithm>
 5 # include <cmath>
 6 # include <queue>
 7 # define LL long long
 8 using namespace std ;
 9 
10 const int maxn = 5010;
11 
12 int sum[maxn<<2] ; //结点开4倍
13 int x[maxn] ;
14 
15 void PushUP(int rt) //更新到父节点
16 {
17     sum[rt] = sum[rt * 2] + sum[rt * 2 + 1] ; //rt 为当前结点
18 }
19 
20 void build(int l , int r , int rt) //构建线段树   所有点都置零
21 {
22     sum[rt] = 0 ;
23     if (l == r)
24     {
25         return ;
26     }
27     int m = (l + r) / 2 ;
28     build(l , m , rt * 2) ;
29     build(m + 1 , r , rt * 2 +1) ;
30 
31 }
32 
33 void updata(int p  , int l , int r , int rt)  //单点增
34 {
35     if (l == r)
36     {
37         sum[rt]++ ;
38         return ;
39     }
40     int m = (l + r) / 2 ;
41     if (p <= m)
42        updata(p , l , m , rt * 2) ;
43     else
44        updata(p  , m + 1 , r , rt * 2 + 1) ;
45     PushUP(rt) ;
46 }
47 
48 int query(int L , int R , int l , int r , int rt)  //区间求和
49 {
50     if (L <= l && r <= R)
51         return sum[rt] ;
52     int m = (l + r) / 2 ;
53     int ret = 0 ;
54     if (L <= m)
55        ret += query(L , R , l , m , rt * 2) ;
56     if (R > m)
57        ret += query(L , R , m + 1 , r , rt * 2 + 1) ;
58     return ret ;
59 }
60 
61 int main ()
62 {
63     //freopen("in.txt","r",stdin) ;
64     int n ;
65     while(scanf("%d" , &n) != EOF)
66     {
67         build(0 , n - 1 , 1) ; //因为序列里有0 所以要从0开始
68         int sum = 0 ;
69         int i ;
70         for (i = 0 ; i < n ; i++)
71         {
72            scanf("%d" , &x[i]) ;
73            sum += query(x[i] , n-1 , 0 , n-1 , 1) ;  //sum累加的是 现在输入的x[i] 和 之前输入的数相比 有几个比它大  也就是逆序
74            updata(x[i] , 0 , n-1 , 1) ;
75         }
76            int ret = sum ;  //当前输入序列的逆序
77         for (i = 0 ; i < n ; i++)   //每次循环 都是将之前的序列的第一位以移到最后一位
78         {
79            sum += n - x[i] - x[i] - 1 ;  //sum为移动后的逆序
80            ret = min(ret , sum) ;
81         }
82         printf("%d\n" , ret) ;
83     }
84 
85     return 0 ;
86 }
View Code

 

hdu 1394 求一个序列的最小逆序数 单点增 区间求和

标签:

原文地址:http://www.cnblogs.com/-Buff-/p/4603211.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!