HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1394

Minimum Inversion Number



Problem Description
 
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)

You are asked to write a program to find the minimum inversion number out of the above sequences.
 
Input
 
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
 
Output
 
For each case, output the minimum inversion number on a single line.
 
Sample Input
 
10 1 3 6 9 0 8 5 7 4 2
 
Sample Output
 
16
 
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 5005
 6 #define lson rt<<1,l,m
 7 #define rson rt<<1|1,m+1,r
 8 struct node
 9 {
10     int l,r,value;
11 }tree[N<<2];
12 int a[N];
13 /*
14 求移位后的最小逆序数
15 Update单点增减
16 Query区间求和
17 */
18 void Build(int rt,int l,int r)
19 {
20     tree[rt].l=l;
21     tree[rt].r=r;
22     tree[rt].value=0;
23     if(l==r) return ;
24     int m=(l+r)>>1;
25     Build(rt<<1,l,m);
26     Build(rt<<1|1,m+1,r);
27 }
28 
29 void Update(int rt,int num)
30 {
31     if(tree[rt].l==num&&tree[rt].r==num){
32         tree[rt].value=1;
33         return ;
34     }
35     int m=(tree[rt].l+tree[rt].r)>>1;
36     if(num<=m) Update(rt<<1,num);
37     else Update(rt<<1|1,num);
38     tree[rt].value=tree[rt<<1].value+tree[rt<<1|1].value;
39 }
40 
41 int Query(int rt,int l,int r)
42 {
43 /*
44 画个图就明白了,搜寻的区间为[l,r],m代表当前节点的左儿子和右儿子的分支
45 如果左儿子有包含该区间的元素,即l<=m,那么就要继续递归搜寻左儿子
46 如果右儿子有包含该区间的元素,即m<r,那么就要继续递归搜寻右儿子
47 当当前的节点的区间被搜寻的区间[l,r]覆盖的话,就说明该段区间完全在[l,r]里面
48 那么返回该节点的值
49 */
50     if(l<=tree[rt].l&&tree[rt].r<=r){
51         return tree[rt].value;
52     }
53     else{
54         int m=(tree[rt].l+tree[rt].r)>>1;
55         int s1=0,s2=0;
56         if(l<=m) s1=Query(rt<<1,l,r);
57         if(r>m) s2=Query(rt<<1|1,l,r);
58         return s1+s2;
59     }
60 }
61 
62 int main()
63 {
64     int n;
65     while(~scanf("%d",&n)){
66         Build(1,1,n);
67         int sum=0;
68         for(int i=0;i<n;i++){
69             scanf("%d",&a[i]);
70             a[i]++;
71             sum+=Query(1,a[i]+1,n);
72             Update(1,a[i]);
73         }
74         int res = sum;
75         for(int i=n-1;i>=0;i--){
76             sum=sum-(n-a[i])+(a[i]-1);
77             if(sum<res) res=sum;
78         }
79         printf("%d
",res);
80     }
81     return 0;
82 }
原文地址:https://www.cnblogs.com/fightfordream/p/5656675.html