Ultra-QuickSort 离散化+树状数组

来源:互联网 发布:安装win10 linux的pe 编辑:程序博客网 时间:2024/05/16 15:22

                                        Ultra-QuickSort

Time Limit : 14000/7000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 32 Accepted Submission(s) : 15
Problem 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
59105431230

Sample Output
60

Source
PKU
TLE代码:
此题大意:找逆序数有多少个,逆序数就是那一个序列中,右边的数比左边的数大的个数之和。其实就是和找冒泡的次数一样,不过用冒泡来做,50万个数据直接死亡,这道题可以用树状数组来做,之前不会做,看到解题报告中有说树状数组可以,就开始尝试写,后来发现竟然可以这样想:每次找前面(左边)的数比自己大的个数的总和!!!这样子想的话树状数组可以轻松解决。      不过还有一个问题,就是他输入的数据的值很大0 ≤ a[i] ≤ 999,999,999,但是数据的数量不是很大n < 500,000 ,所以用到离散化解决!!!链接:http://poj.org/problem?id=2299代码:Cpp代码  #include <iostream>   #include <stdio.h>   #include <cmath>   #include <algorithm>   using namespace std;     int b[500005], c[500005];   int n;     struct node   {       int num, id;   }a[500005];     bool cmp(node a, node b)   {       return a.num < b.num;   }     void update(int i, int x)   {       while(i <= n)       {           c[i] += x;           i += i&(-i);       }   }     int sum(int i)   {       int sum = 0;       while(i > 0)       {           sum += c[i];           i -= i&(-i);       }       return sum;   }     int main()   {       int i;       long long ans;       while(scanf("%d", &n), n)       {           memset(b, 0, sizeof(b));           memset(c, 0, sizeof(c));           for(i = 1; i <= n; i++)           {               scanf("%d", &a[i].num); //输入数值num               a[i].id = i;            //记录序号id           }           ///开始离散化           sort(a+1, a+n+1, cmp);  //先排序           /*因为a[1].num是最小的,id是它的位置,所以b[a[1].id]=1最小,            最小的数变成1,第二小的变成2,如此类推从而达到离散化*/          b[a[1].id] = 1;           for(i = 2; i <= n; i++)           {               if(a[i].num != a[i-1].num)                   b[a[i].id] = i;               else b[a[i].id] = b[a[i-1].id];           }           ///离散化完毕           ans = 0;           for(i = 1; i <= n; i++)           {               update(b[i], 1);               //这里很巧妙,每一次更新后,判断此数比左边的数小的数有多少               ans += (sum(n)-sum(b[i]));           }           //从而求到:右边的数比左边的数大的个数的总和           printf("%I64d\n", ans);       }         return 0;   }