线段树单点更新 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 }

 

你可能感兴趣的:(version)