POJ 2299 Ultra-QuickSort (树状数组+离散化 求逆序数)

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

59 1 0 5 431 2 3
0

Sample Output

6
0

给你一个排序,让你求出这个排序中的逆序数.算是自己写的树状数组的第一道题吧,这个题首先用到离散化思想.因为每个数都是小于1e9,而n的范围不超过5e5,而且我们只关心这些数的大小关系,所以我们就把这些数全部映射到1~n,然后再按照排好序的位置插进去就行了这样子是不会影响最后算逆序数的.映射后的序列为reflect接下来求逆序数,这时要用到树状数组,树状数组的功能是用来求数组前缀和的,我们假想有一个长度为n的数组,它现在每一位初始化为0我们按照位置顺序将reflect中的每一个数插入到树状数组中,假设我们现在插入的数是第i个数,它的值为x那么我就把刚刚假想的数组的第x位置变为1,即代表x被插入到该序列那么每一次对于ans怎样+呢?我们可以定义sum(x) x及小于x的数中有多少个元素已经被插入这样的话sum(x)就是我们刚刚那个假想数组的前缀和了,我们用树状数组可以求对于插入的第i个数,我们的ans+=i-sum(x),因为x是第i个数插进来的,之前插进来小于等于x的数为sum(x)两者做差就是在x之前插入,而且值要大于x的数字的个数代码如下:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn =550000;
 7 int reflect[maxn];
 8 int c[maxn];
 9 int n;
10 int lowbit (int x)
11 {
12     return x&(-x);
13 }
14 struct Node
15 {
16     int val,pos;
17 };
18 Node node[maxn];
19 bool cmp (Node q1,Node q2)
20 {
21     return q1.val<q2.val;
22 }
23
24 void update (int x)
25 {
26     while (x<=n){
27         c[x]+=1;//将我们想象的数组x位置附为1,直接就加到c[x]上了
28         x+=lowbit(x);//找父节点
29     }
30 }
31 int getsum (int x)
32 {
33     int sum=0;
34     while (x>0){
35         sum+=c[x];
36         /*求和时可以看作将x用二进制表示
37         temp=x;
38         每次加上c[temp],再把temp最后1位置上的值改成0
39           最后变成0时就求完了
40           如:求 101001
41            temp=101001 ->  sum+=c[101001]
42         -> temp=101000 ->  sum+=c[101000]
43         -> temp=100000 ->  sum+=c[100000]
44         -> temp=000000    求完了
45         */
46         x-=lowbit(x);
47     }
48     return sum;
49 }
50 int main()
51 {
52     //freopen("de.txt","r",stdin);
53     while (scanf("%d",&n)&&n){
54         for (int i=1;i<=n;++i){
55             scanf("%d",&node[i].val);
56             node[i].pos=i;
57         }
58         sort(node+1,node + n + 1, cmp);
59         for (int i=1;i<=n;++i) reflect[node[i].pos]=i;//离散化映射到1~n
60         for (int i=0;i<=n;++i) c[i]=0;//初始化树状数组
61         long long ans=0;
62         for (int i=1;i<=n;++i){
63             update(reflect[i]);//插入一个数,更新一下
64             ans+=i-getsum(reflect[i]);//ans加一下
65         }
66         printf("%lld\n",ans);
67     }
68     return 0;
69 }
 
时间: 2024-10-19 12:17:56

POJ 2299 Ultra-QuickSort (树状数组+离散化 求逆序数)的相关文章

HDU 1394 树状数组+离散化求逆序数

对于求逆序数问题,学会去利用树状数组进行转换求解方式,是很必要的. 一般来说我们求解逆序数,是在给定一串序列里,用循环的方式找到每一个数之前有多少个比它大的数,算法的时间复杂度为o(n2). 那么我们通过树状数组可以明显提高时间效率. 我们可以按照排列的顺序依次将数字放入树状数组中,并依次更新预与之相关联的树状数组元素.那么在将其更新完毕后,我们知道每个数对应的树状数组元素的左边的数肯定比它小,我们在以序列顺序依次更新树状数组时,如果有值在它前面出现,那么它对应的树状数组元素(在这个题目里存放的

POJ 2299 Ultra-QuickSort(树状数组+离散化)

http://poj.org/problem?id=2299 题意:给出一组数,求逆序对. 思路: 这道题可以用树状数组解决,但是在此之前,需要对数据进行一下预处理. 这道题目的数据可以大到999,999,999,但数组肯定是无法开这么大的,但是每组数据最多只有500000个,那么,怎么办呢,离散化! 离散化,也就是将数据和1~n做一一映射. 比如: 9 1 0 5 4 离散化之后变成 5 2 1 4 3 这样的话,就可以放心的开数组啦! 至于树状数组的计算过程,我懒得写了,直接摘抄一下大神的h

POJ2299 Ultra-QuickSort【树状数组】【逆序数】

题目链接: http://poj.org/problem?id=2299 题目大意: 给你一个包含N个整数的序列,只能通过交换相邻的数字,最终变为升序顺序,问:最少需要多少次交换. 思路: 其实就是问冒泡排序的交换次数.其实就是求原序列的逆序数.用归并排序.线段树.树状数组都可以做. 但是如果用线段树和树状数组来做的话,因为元素个数是500000,但是元素值范围却是999999999,需 要先离散化.这里用间接排序的方法.用一个数组Arr[]存放原序列的值,另一个数组Id[]存放原序列编号 (1

poj 2299 Ultra-QuickSort (树状数组+离散化)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 48257   Accepted: 17610 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)

题目链接:http://poj.org/problem?id=2299 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

POJ 2299 Ultra-QuickSort (树状数组)

前段时间用归并排序写了这题,发现树状数组也能解这题,就去学习了一下 首先先来看一个序列   6 1 2 7 3 4 8 5,此序列的逆序数为5+3+1=9.冒泡法可以直接枚举出逆序数,但是时间复杂度太高O(n^2).冒泡排序的原理是枚举每一个数组,然后找出这个数后面有多少个数是小于这个数的,小于它逆序数+1.仔细想一下,如果我们不用枚举这个数后面的所有数,而是直接得到小于这个数的个数,那么效率将会大大提高. 总共有N个数,如何判断第i+1个数到最后一个数之间有多少个数小于第i个数呢?不妨假设有一

poj 2299 Ultra-QuickSort(线段树/树状数组/归并 求逆序对)

Problem: 2299 User: shu_dayang Memory: 7380K Time: 500MS Language: C++ Result: Accepted Source Code//树状数组 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> typedef long long LL; #define MAXN 500005 #define M

POJ 2299 Ultra-QuickSort(树状数组)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 47014   Accepted: 17182 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

POJ3067 Japan【树状数组】【逆序数】

题目链接: http://poj.org/problem?id=3067 题目大意: 有两排的城市,一排N个城市,编号为1~N,一排M个城市,编号为1~M.这两排城市之间有K条路. 路都是直线连接,问:这些路,有多少道路是相交的,并且焦点不是城市所在的点,求出交点个数. 思路: 树状数组的思想.参考网上的图,先将所有边(u,v)按u升序排列,如果u相同,则按v升序排列.可 以看出来,路(u1,v1)和路(u2,v2)如果有交点的话,u1 > u2 并且 v1 < v2,或者 u1 < u