poj2299_树状数组

题意:求逆序对。

分析:以前用分治的思想写的,这次用树状数组。

以array[]=9 1 0 5 4 为例,

1.对于每个array[i],求出小于等于array[i]的个数:

9:1

1:1

0:1

5:3

4:3个

这里如果遍历求的话,就超时了。因此需要构建树状数组,树状数组需要离散化。有:
array[] 9 1 0 5 4

num    1 2 3 4 5

这里不压缩要1--n内有时也行,如果数据小的话。

比如这个例子就行,离散到大于等于1就行。

但是如果数据大的话,就得压缩压下。

2.用树状数组求小于等于array[i]的个数应该以array[]由小到大排序遍历

i          1 2 3 4 5

array   0 1 4 5 9

num    3 2 5 4 1

array[]排序后也对应了num的一个顺序

依次对num进行更新,就可以tree[i]求出的就是小于等于array[i]的个数

3.用已经排序的对应的i-tree[i],即i-小于等于array[i]的个数的总和就是逆序数个数。

4.总结:关键是树状数组的构建,这里树状数组是用来求小于等于array[i]的个数的。

代码:

树状数组500ms

View Code
 1 #include <iostream>

 2 #include <stdio.h>

 3 #include <algorithm>

 4 #include <memory.h>

 5 using namespace std;

 6 //500ms

 7 const int maxnum=500000;

 8 struct node

 9 {

10     int digit;

11     int num;

12 }array[maxnum];

13 int tree[maxnum];

14 int n;

15 

16 bool cmp(struct node a,struct node b)

17 {

18     return a.digit<b.digit;

19 }

20 

21 void update(int index,int add)

22 {

23     while(index<=n)  //  1.是<=n

24     {

25         tree[index]+=add;

26         index+=((-index)&index);

27     }

28 }

29 

30 int getsum(int index)

31 {

32     int sum=0;

33     while(index>0)

34     {

35         sum+=tree[index];

36         index-=((-index)&index);

37     }

38     return sum;

39 }

40 

41 int main()

42 {

43     int i;

44     __int64 sum;

45     while(scanf("%d",&n) && n!=0)

46     {

47         for(i=1;i<=n;i++)

48         {

49             scanf("%d",&array[i].digit);

50             array[i].num=i;

51         }

52         sort(array+1,array+n+1,cmp);

53 

54         memset(tree,0,sizeof(tree)); //初始化树状数组

55         sum=0;

56         for(i=1;i<=n;i++)

57         {

58             update(array[i].num,1);

59             sum+=(i-getsum(array[i].num));

60         }

61         printf("%I64d\n",sum);

62     }

63     return 0;

64 }

65 

66 /*

67 5

68 9 1 0 5 4

69 */

分治1282ms

View Code
 1 #include <iostream>

 2 

 3 using namespace std;

 4 const int maxnum=1000000000;

 5 int a[500005];

 6 int larray[250005];

 7 int rarray[250005];

 8 long long cnt;   //这里是long long 否则wa

 9 

10 void Merge(int p,int q,int r)

11 {

12     int i;

13     int llen=q-p+1;

14     int rlen=r-q;

15     for(i=0;i<llen;i++)

16         larray[i]=a[p+i];

17     for(i=0;i<rlen;i++)

18         rarray[i]=a[q+1+i];

19     larray[llen]=maxnum;

20     rarray[rlen]=maxnum;

21 

22     int j,k;

23     i=0;j=0;

24     for(k=p;k<=r;k++)

25     {

26         if(larray[i]<=rarray[j])

27         {

28             a[k]=larray[i];

29             i++;

30         }

31         else

32         {

33             a[k]=rarray[j];

34             j++;

35             cnt+=llen-i;

36         }

37     }

38 }

39 

40 void Merge_Sort(int p,int r)

41 {

42     if(p<r)

43     {

44         int q=(p+r)/2;

45         Merge_Sort(p,q);

46         Merge_Sort(q+1,r);

47         Merge(p,q,r);

48     }

49 }

50 

51 int main()

52 {

53     int num,i;

54     while(cin>>num)

55     {

56         if(num==0) break;

57         for(i=0;i<num;i++)

58             cin>>a[i];

59         cnt=0;

60         Merge_Sort(0,num-1);

61         cout<<cnt<<endl;

62     }

63     return 0;

64 }

 

tjuoj 1455

你可能感兴趣的:(树状数组)