线段树单点更新 HDU 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
 
题意:求最小逆序数。

分析:线段树的一个应用,求逆序数。

从a[0]开始扫描,找比a[0]大的个数,也就是询问区间(a[0],n-1)中点的个数,然后再插入a[0],更新父节点即可。

思路为:tree[i]为0代表i未出现,为1则已经出现,
然后查询时我们只要统计新加入的数到n-1这个范围内有多少个tree[i]为1,也就是当前
数的逆序,然后累加,就是我们要求的逆序数。因为其他形式都可以由第一次求得的逆
序数递推而来,所以只需计算一次。

有个结论,设逆序数为sum,x[0]后面比它小的一定是x[0]个。那么移到末尾后,比x[0]大的数的后面比它小的数统统加一,也就是加(n - a[0] - 1),然后它放到末尾了,他原来的后面比它小的数变为0,也就是sum = sum + (n - a[0] - 1) - a[0];

AC代码:

View Code
 1 #include<stdio.h>
 2 #define maxn 5010
 3 #define lson l,m,rt << 1
 4 #define rson m+1,r,rt << 1 | 1
 5 int tree[maxn<<2],x[maxn];
 6 int min(int a,int b)
 7 {
 8     return a<b?a:b;
 9 }
10 void PushUP(int rt)
11 {
12     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
13 }
14 void build(int l,int r,int rt)
15 {
16     tree[rt]=0;
17     if(l==r)
18         return ;
19     int m=(l+r)>>1;
20     build(lson);
21     build(rson);
22 }
23 int query(int L,int R,int l,int r,int rt)
24 {
25     if(L<=l&&R>=r)
26         return tree[rt];
27     int m=(l+r)>>1;
28     int ret=0;
29     if(L<=m)
30         ret+=query(L,R,lson);
31     if(R>m)
32         ret+=query(L,R,rson);
33     return ret;
34 }
35 void update(int p,int l,int r,int rt)
36 {
37     if(l==r)
38     {
39         tree[rt]++;
40         return ;
41     }
42     int m=(l+r)>>1;
43     if(p<=m)
44         update(p,lson);
45     else
46         update(p,rson);
47     PushUP(rt);
48 }
49 int main()
50 {
51     int i,n,sum;
52     while(scanf("%d",&n)!=EOF)
53     {
54         build(0,n-1,1);
55         sum=0;
56         for(i=0;i<n;i++)
57         {
58             scanf("%d",&x[i]);
59             sum+=query(x[i],n-1,0,n-1,1);
60             update(x[i],0,n-1,1);
61         }
62         int ret=sum;
63         for(i=0;i<n;i++)
64         {
65             sum+=n-x[i]-1-x[i];
66             ret=min(ret,sum);
67         }
68         printf("%d\n",ret);
69     }
70     return 0;
71 }

 

posted on 2012-09-01 19:02  jumpingfrog0  阅读(373)  评论(0编辑  收藏  举报

导航