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

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

Description

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
",ans);
63     }
64 
65     return 0;
原文地址:https://www.cnblogs.com/CXCXCXC/p/4626604.html