用树状数组求逆序对数(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.
Ultra-QuickSort produces the output
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;