HDU1394

题目链接:https://vjudge.net/problem/HDU-1394

题目分析:先用线段树求出第一个数组的逆序数,其他的数组的逆序数可以用公式直接求出

     用线段树求出数组逆序数的思路:把数组a[]上的元素逐个插入线段树,以元素的大小作为插入位置,则在其插入位置的右方的叶子数即为数组中的这个元素之前的比这个元素本身大的数。一开始初始化逆序数为0,然后每次插入都把元素右方的叶子数加上去,最后就可以得到数组的逆序数了。

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int maxn=5000+5;
 6 int sum[maxn<<2];
 7 
 8 void PushUp(int rt){
 9     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
10 }
11 void build(int l,int r,int rt){
12     if(l==r){
13         sum[rt]=0;
14         return;
15     }
16     int m=(l+r)>>1;
17     build(l,m,rt<<1);
18     build(m+1,r,rt<<1|1);
19     PushUp(rt);
20 }
21 void update(int p,int l,int r,int rt){
22     if(l==p&&r==p){
23         sum[rt]=1;
24         return;
25     }
26     int m=(l+r)>>1;
27     if(p<=m)    update(p,l,m,rt<<1);
28     else    update(p,m+1,r,rt<<1|1);
29     PushUp(rt);
30 }
31 int query(int L,int R,int l,int r,int rt){
32     if(l>L&&R>=r){
33         return sum[rt];
34     }
35     int m=(l+r)>>1;
36     int ret=0;
37     if(L<m)   ret+=query(L,R,l,m,rt<<1);
38     if(R>m)    ret+=query(L,R,m+1,r,rt<<1|1);
39     return ret;
40 }
41 int main(){
42     int N;
43     int a[maxn];
44 
45     while(scanf("%d",&N)==1){
46         for(int i=0;i<N;i++)
47             scanf("%d",&a[i]);
48         build(0,N-1,1);
49         int ans=0;
50         for(int i=0;i<N;i++){
51             update(a[i],0,N-1,1);
52             ans+=query(a[i],N-1,0,N-1,1);
53         }
54         int temp=ans;
55         for(int i=0;i<N;i++){
56             temp=temp-a[i]+(N-1-a[i]);
57             ans=min(ans,temp);
58         }
59         printf("%d\n",ans);
60     }
61     return 0;
62 }
View Code

 

posted @ 2017-06-11 16:35  Blogggggg  阅读(182)  评论(0编辑  收藏  举报