poj2299_树状数组II
这个题做过了,今天是树状数组的另一个版本。
分析:
例如 9 1 0 5 4
一般数据小的话,我们求每个数字前面小于等于它的个数,只需要离散到大于等于1的范围内。
9: update(10),sum(10) --->1
1: update(2),sum(2)--->1
0: update(1),sum(0)--->1
5: update(6),sum(6)--->3
4: update(5),sum(5)--->3
但是这个题数据范围很大,因此必须得压缩一下
注意到 9在序列中第5大,1第2大,。。。。
因此,将 9 1 0 5 4替换成5 2 1 4 3做树状数组是不变的
然后对应的5-1;2-1;1-1;4-3;3-3;求和就可得逆序数。
代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <memory.h> 5 using namespace std; 6 const int maxnum=500000; 7 struct node 8 { 9 int digit; 10 int num; 11 }array[maxnum],temp[maxnum]; 12 int tree[maxnum]; 13 int n; 14 15 bool cmp(struct node a,struct node b) 16 { 17 return a.digit<b.digit; 18 } 19 20 void update(int index,int add) 21 { 22 while(index<=n) // 1.是<=n 23 { 24 tree[index]+=add; 25 index+=((-index)&index); 26 } 27 } 28 29 int getsum(int index) 30 { 31 int sum=0; 32 while(index>0) 33 { 34 sum+=tree[index]; 35 index-=((-index)&index); 36 } 37 return sum; 38 } 39 40 41 int main() 42 { 43 int i; 44 long long sum; 45 while(scanf("%d",&n) && n!=0) 46 { 47 for(i=1;i<=n;i++) 48 { 49 scanf("%d",&array[i].digit); 50 temp[i].digit=array[i].digit; 51 temp[i].num=i; 52 } 53 sort(temp+1,temp+n+1,cmp); 54 for(i=1;i<=n;i++) 55 array[temp[i].num].num=i; 56 memset(tree,0,sizeof(tree)); //初始化树状数组 57 sum=0; 58 for(i=1;i<=n;i++) 59 { 60 update(array[i].num,1); 61 sum+=(array[i].num-getsum(array[i].num)); 62 } 63 printf("%I64d\n",sum); 64 //cout<<sum<<endl; 65 } 66 return 0; 67 }