POJ2299-Ultra-QuickSort(树状数组+离散化)
来源:互联网 发布:同和行知职业技术学校 编辑:程序博客网 时间:2024/06/05 20:05
POJ2299 原题链接:http://poj.org/problem?id=2299
Description
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
Output
Sample Input
59105431230
Sample Output
60
原题大意:输入一串数据,求它的逆序数;
思路:暴力的方法肯定超时,用树状数组可以将复杂度降到O(nlogn);
这道题大体的思路为:
1.开一个能大小为这些数的最大值的树状数组,并全部置0;
2.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum;
3.用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是总的逆序对数;
但是,题目给的一个数的范围最大为999,999,999显然我们的树状数组不能开到那么大;这里要用到离散化,就是把输入的所有数离散化到1~n的范围内在进行1~3步的操作;
离散化过程:
1.创建一个结构体
const int N=5e5+10;typedef struct{ int val; //输入值 int pos; //原下标}NODE;NODE node[N];在创建一个数组a[N];
把node[N]按照val的值从小到大排列之后令 a[node[i].pos]=i (i=1,2,3,4,5,6...n)
过程如下:
1.拿题目第一个样例,输入的为 val: 9 1 0 5 4;
其原下标为pos: 1 2 3 4 5;
node[i]的 i: 1 2 3 4 5;
2.排序之后 val: 0 1 4 5 9
pos: 3 9 5 4 1
i: 1 2 3 4 5
3.执行a[node[i].pos]=i (i=1,2,3,4,5,6...n)后:
i: 1 2 3 4 5;
a[i]: 5 2 1 4 3;
pos[i].val: 9 1 0 5 4;
如上所示,这样做就将1~9缩小为了1~5且大小关系不变的存储在了a[i]中;这时我们可以忽视掉原数组了,因为大小关系不变的话逆序数的对数也不会改变;
那么问题来了,这道题该如何使用树状数组求解呢?
由于a[i]中储存的数是按照原输入的大小关系存储的,那么我们可以:.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum;
还是拿样例:
- 如果数据不是很大, 可以一个个插入到树状数组中,
- 每插入一个数, 统计比他小的数的个数,
- 对应的逆序为 i- sum( a[i] ),
- 其中 i 为当前已经插入的数的个数,
- sum( a[i] )为比 a[i] 小的数的个数,
- i- sum( a[i] ) 即比 a[i] 大的个数, 即逆序的个数
- 但如果数据比较大,就必须采用离散化方法
- 假设输入的数组是9 1 0 5 4, 离散后的结果a[] = {5,2,1,4,3};
- 在离散结果中间结果的基础上,那么其计算逆序数的过程是这么一个过程。
- 1.输入5, 调用add(5, 1),把第5位设置为1
- 1 2 3 4 5
- 0 0 0 0 1
- 计算1-5上比5小的数字存在么? 这里用到了树状数组的sum(5) = 1操作,
- 现在用输入的下标1 -sum(5) = 0 就可以得到对于5的逆序数为0。
- 2. 输入2, 调用add(2, 1),把第2位设置为1
- 1 2 3 4 5
- 0 1 0 0 1
- 计算1-2上比2小的数字存在么? 这里用到了树状数组的sum(2) = 1操作,
- 现在用输入的下标2 - sum(2) = 1 就可以得到对于2的逆序数为1。
- 3. 输入1, 调用add(1, 1),把第1位设置为1
- 1 2 3 4 5
- 1 1 0 0 1
- 计算1-1上比1小的数字存在么? 这里用到了树状数组的sum(1) = 1操作,
- 现在用输入的下标 3 -sum(1) = 2 就可以得到对于1的逆序数为2。
- 4. 输入4, 调用add(4, 1),把第5位设置为1
- 1 2 3 4 5
- 1 1 0 1 1
- 计算1-4上比4小的数字存在么? 这里用到了树状数组的sum(4) = 3操作,
- 现在用输入的下标4 - sum(4) = 1 就可以得到对于4的逆序数为1。
- 5. 输入3, 调用add(3, 1),把第3位设置为1
- 1 2 3 4 5
- 1 1 1 1 1
- 计算1-3上比3小的数字存在么? 这里用到了树状数组的sum(3) = 3操作,
- 现在用输入的下标5 - sum(3) = 2 就可以得到对于3的逆序数为2。
- 6. 0+1+2+1+2 = 6 这就是最后的逆序数
- 分析一下时间复杂度,首先用到快速排序,时间复杂度为O(NlogN),
- 后面是循环插入每一个数字,每次插入一个数字,分别调用一次add()和sum()
- 外循环N, add()和sum()时间O(logN) => 时间复杂度还是O(NlogN)
以上摘自:http://blog.csdn.net/guhaiteng/article/details/52138756(自己还是太菜,无法用自己的语言描述出来
以下为我的ac代码:
#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int N=5e5+10;typedef struct{ int val; int pos;}NODE;NODE node[N];int n;int a[N];int tree[N];bool cmp(const NODE& a, const NODE& b){ return a.val<b.val;}void add(int i){ while(i<=n) { tree[i]+=1; i=i+(i&-i); }}int sum(int i){ int s=0; while(i>0) { s=s+tree[i]; i=i-(i&-i); } return s;}int main(){ while((scanf("%d",&n))!=EOF) { if(n==0) break; for(int i=1;i<=n;i++) { scanf("%d",&node[i].val); node[i].pos=i; } sort(node+1,node+n+1,cmp);//排序 for(int i=1;i<=n;i++) a[node[i].pos]=i; //离散化 for(int i=1;i<=n;i++) tree[i]=0; //初始化树状数组 long long ans=0; for(int i=1;i<=n;i++) { add(a[i]); ans+=i-sum(a[i]); } cout<<ans<<endl; }}
- poj2299 Ultra-QuickSort (树状数组+离散化)
- POJ2299 Ultra-QuickSort 树状数组+离散化
- poj2299 Ultra-QuickSort 树状数组 + 离散化
- POJ2299-Ultra-QuickSort(树状数组+离散化)
- poj2299:Ultra-QuickSort(树状数组+离散化)
- poj2299 Ultra-QuickSort(归并排序 || 离散化+树状数组)
- 【树状数组】poj2299 Ultra-QuickSort(离散化+树状数组求逆序数)
- 【树状数组】 poj2299 Ultra-QuickSort
- POJ2299 Ultra-QuickSort(树状数组)
- poj2299 Ultra-QuickSort 树状数组
- POJ2299 Ultra-QuickSort 树状数组
- poj2299 Ultra-QuickSort 树状数组
- POJ2299 Ultra-QuickSort(树状数组)
- POJ2299 Ultra-QuickSort 【树状数组】
- POJ2299 Ultra-QuickSort——树状数组求逆序数+离散化
- poj2299 Ultra-QuickSort(树状数组求逆序数,离散化)
- poj2299 Ultra-QuickSort&&NYOJ117 求逆序数 (树状数组求逆序对数+离散化)+(归并排序)
- poj2299 Ultra-QuickSort(离散化+树状数组求逆序数)
- 乌鲁木齐网络赛J题(最小费用最大流模板)
- byte数据类型的初步入门
- 【2017新疆网络赛】E Half-consecutive Numbers 打表
- Linux安装PhpStorm
- Python学习之初始(四)
- POJ2299-Ultra-QuickSort(树状数组+离散化)
- LeetCode笔记:(Java) 9. Palindrome Number
- java中String、StringBuffer、StringBuilder的区别
- Android 手机卫士(4) 包名/版本号/版本名的获取
- ListView 缓存机制源码浅析
- HDU-5493---Queue (线段树)
- Binary Tree Tilt
- 20170914
- 高阶函数