用树状数组求逆序对数(poj2299)

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 46995   Accepted: 17168

Description

用树状数组求逆序对数(poj2299)In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 
9 1 0 5 4 ,

Ultra-QuickSort produces the output 
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5

9

1

0

5

4

3

1

2

3

0

Sample Output

6

0

Source

           题目大意:给定若干个序列,假设是a[],求满足a[i]>a[j],且0<=i<j<=N的i,j的对数。
           首先,暴力的方法应该很好想,只要枚举每一个a[i],在枚举a[j](0<j<=i-1),若a[j]>a[i],则ans++。
          
           但是,这题给的序列的长度达到50w,若用暴力,时间复杂度为O(n^2),时间上过不了。为此可以针对这个序列中的数字大小区间做一个树状数组,按顺序把序列元素加进去,统计比它小的数字的个数,累加起来即可,时间复杂度O(nlogn),轻松通过。
 
           再但是,每个数字大小达到近百亿,若针对每个数字建立一个树状数组,空间上开不下(题目上只给了64M内存),所以要用离散化来解决(离散化讲解:http://baike.baidu.com/view/3392254.htm)具体方法是:先用结构体暂时存储序列,记下大小和位置,然后快排一下(虽然快排在序列完全逆序时可能卡到O(n^2),但是出题人要是在这卡你的话就太 *¥#&%&),再开一个reflect[],记录下离散化后的序列,这样若有50w个数,即使都很大,也终究有个大小之分,可以离散成1~50w,数组开至百万完全无压力。。
         
           就这样,时间和空间的问题都解决了。。。
 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstdlib>

 4 #include<algorithm>

 5 #include<cmath>

 6 using namespace std;  7 typedef long long LL;  8 int N,M;  9 struct node{ 10     int val;//记录大小 

11     int pos;//记录这个数字的位置,方便以后排序 

12 }; 13 node a[1000000];//暂时存储序列 

14 int reflect[1000000];//离散化后的序列 

15 int BIT[10000000];//树状数组 

16 

17 int cmp(const node &u,const node &v){ 18     if(u.val<v.val) return 1; 19     return 0; 20 } 21 

22 int lowbit(int x){ 23     return x&(-x); 24 } 25 /*

26 update 27 把数字依次插入,而不是直接建树的原因: 28 我们目的是求之前比当前数字小的数字个数,这样可以做到 29 ans+=i-sum(reflect[i])来更新,直接建树。。。不行 30 */

31 

32 void update(int x){ 33     for(int i=x;i<=N;i+=lowbit(i)){ 34         BIT[i]++; 35  } 36 } 37 

38 int sum(int k){ 39     int ANS=0; 40     for(int i=k;i>0;i-=lowbit(i)){ 41         ANS+=BIT[i]; 42  } 43     return ANS; 44 } 45 int main(){ 46     while(scanf("%d",&N)!=EOF&&N){ 47        for(int i=1;i<=N;i++){ 48            scanf("%d",&a[i].val); 49            a[i].pos=i; 50  } 51        sort(a+1,a+N+1,cmp); 52     

53        for(int i=1;i<=N;i++) 54            reflect[a[i].pos]=i;//离散化 

55        for (int i = 1; i <= N; ++i) BIT[i] = 0; 56           //清空树状数组,,,千万不要忘记

57         LL ans=0; 58         for(int i=1;i<=N;i++){ 59  update(reflect[i]); 60         ans+=(i-sum(reflect[i])); 61  } 62         printf("%lld\n",ans); 63  } 64 

65     return 0;

 

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