POJ 2299 Ultra-QuickSort (树状数组 && 离散化&&逆序)
题意 : 给出一个数n(n<500,000), 再给出n个数的序列 a1、a2.....an每一个ai的范围是 0~999,999,999 要求出当通过相邻两项交换的方法进行升序排序时需要交换的次数
分析:其实经过一次模拟后,会发现奇妙的东西,这个排序都是按位置排的,最大要求到最大,最小要去到最小,转化思想这是一道求逆序对数的题目,答案就是逆序对数。
这里数据过大999999999,数组无法开的了这么大,我们可以离散化,只记录相对大小。
这里离散化有所不同,这里为了压时,用了空间换时间的方法. 前面的文章有讲到sum(i)表示前面有多少比这个小的数,可以sum(n)-sum(i), 这里有新知识就是sum(i)表示有多少小的数,那当前的总数是i,那大的数就是(i-sum(i)这也是求逆序对的方法,目测挺快的。
.解释为什么要有离散的这么一个过程?
刚开始以为999..999这么一个数字,对于int存储类型来说是足够了。
还有只有500000个数字,何必要离散化呢?
刚开始一直想不通,后来明白了,后面在运用树状数组操作的时候,
用到的树状数组C[i]是建立在一个有点像位存储的数组的基础之上的,
不是单纯的建立在输入数组之上。
比如输入一个9 ,那么C[i]树状数组的建立是在, 数据: p[i].val
编号: p[i].oder = i*************
sort
数据:
编号:
顺序: a[p[i].编号] = 顺序号;********************** a[] = <--;
a[] = <--;
a[] = <--;
a[] = <--;
a[] = <--; a[]={ } 新号:
值 : 下标
数组
现在由于999999999这个数字相对于500000这个数字来说是很大的,
所以如果用数组位存储的话,那么需要999999999的空间来存储输入的数据。
这样是很浪费空间的,题目也是不允许的,所以这里想通过离散化操作,
使得离散化的结果可以更加的密集。
简言之就是开一个大小为这些数的最大值的树状数组
. 怎么对这个输入的数组进行离散操作?
离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围;
因为其中需排序的数的范围0--- ;显然数组不肯能这么大;
而N的最大范围是500 ;故给出的数一定可以与1.。。。N建立一个一一映射;
()当然用map可以建立,效率可能低点;
()这里用一个结构体
struct Node
{
int val,pos;
}p[];和一个数组a[]; 其中val就是原输入的值,pos是下标;
然后对结构体按val从小到大排序; 此时,val和结构体的下标就是一个一一对应关系,
而且满足原来的大小关系; for(i=;i<=N;i++)
a[p[i].pos]=i; 然后a数组就存储了原来所有的大小信息;
比如 ------- 离散后aa数组
就是 ;
具体的过程可以自己用笔写写就好了。 . 离散之后,怎么使用离散后的结果数组来进行树状数组操作,计算出逆序数?
如果数据不是很大, 可以一个个插入到树状数组中,
每插入一个数, 统计比他小的数的个数,
对应的逆序为 i- sum( a[i] ),
其中 i 为当前已经插入的数的个数,
sum( a[i] )为比 a[i] 小的数的个数,
i- sum( a[i] ) 即比 a[i] 大的个数, 即逆序的个数
但如果数据比较大,就必须采用离散化方法
假设输入的数组是9 , 离散后的结果a[] = {,,,,};
在离散结果中间结果的基础上,那么其计算逆序数的过程是这么一个过程。
.输入5, 调用add(, ),把第5位设置为1 计算1-5上比5小的数字存在么? 这里用到了树状数组的sum() = 1操作,
现在用输入的下标1 -sum() = 就可以得到对于5的逆序数为0。
. 输入2, 调用add(, ),把第2位设置为1 计算1-2上比2小的数字存在么? 这里用到了树状数组的sum() = 1操作,
现在用输入的下标2 - sum() = 就可以得到对于2的逆序数为1。
. 输入1, 调用add(, ),把第1位设置为1 计算1-1上比1小的数字存在么? 这里用到了树状数组的sum() = 1操作,
现在用输入的下标 -sum() = 就可以得到对于1的逆序数为2。
. 输入4, 调用add(, ),把第5位设置为1 计算1-4上比4小的数字存在么? 这里用到了树状数组的sum() = 3操作,
现在用输入的下标4 - sum() = 就可以得到对于4的逆序数为1。
. 输入3, 调用add(, ),把第3位设置为1 计算1-3上比3小的数字存在么? 这里用到了树状数组的sum() = 3操作,
现在用输入的下标5 - sum() = 就可以得到对于3的逆序数为2。
. ++++ = 这就是最后的逆序数
分析一下时间复杂度,首先用到快速排序,时间复杂度为O(NlogN),
后面是循环插入每一个数字,每次插入一个数字,分别调用一次add()和sum()
外循环N, add()和sum()时间O(logN) => 时间复杂度还是O(NlogN)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+; struct node{
int val;
int pos;
}p[N]; int n,bit[N],a[N]; bool cmp(const node&a, const node& b){
return a.val<b.val;
} void add(int i){
while(i<=n){
bit[i]+=;
i+=i&-i;
}
} int sum(int i){
int s=;
while(i>){
s+=bit[i];
i-=i&-i;
}
return s;
} void solve(){
for(int i=; i<=n; i++){
scanf("%d",&p[i].val);
p[i].pos=i;
}
sort(p+,p+n+,cmp);//排序
for(int i=; i<=n; i++)a[p[i].pos]=i;//离散化
ll ans=;
for (int i=; i<=n; i++) bit[i]=; //初始化树状数组
for(int i=; i<=n; i++){
add(a[i]);
ans+=i-sum(a[i]);
}
printf("%I64d\n",ans);
} int main(){
while(~scanf("%d",&n)&&n){
solve();
}
return ;
}
POJ 2299 Ultra-QuickSort (树状数组 && 离散化&&逆序)的更多相关文章
- poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)
题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...
- poj 2299 Ultra-QuickSort(树状数组求逆序数)
链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...
- POJ 2299 Ultra-QuickSort(树状数组+离散化)
http://poj.org/problem?id=2299 题意:给出一组数,求逆序对. 思路: 这道题可以用树状数组解决,但是在此之前,需要对数据进行一下预处理. 这道题目的数据可以大到999,9 ...
- POJ - 2299 Ultra-QuickSort 【树状数组+离散化】
题目链接 http://poj.org/problem?id=2299 题意 给出一个序列 求出 这个序列要排成有序序列 至少要经过多少次交换 思路 求逆序对的过程 但是因为数据范围比较大 到 999 ...
- POJ 2299 Ultra-QuickSort【树状数组 ,逆序数】
题意:给出一组数,然后求它的逆序数 先把这组数离散化,大概就是编上号的意思--- 然后利用树状数组求出每个数前面有多少个数比它小,再通过这个数的位置,就可以求出前面有多少个数比它大了 这一篇讲得很详细 ...
- Ultra-QuickSort(树状数组求逆序对数)
Ultra-QuickSort 题目链接:http://poj.org/problem?id=2299 Time Limit: 7000MS Memory Limit: 65536K Total ...
- hdu2838树状数组解逆序
离散化和排序后的序号问题搞得我实在是头痛 不过树状数组解逆序和偏序一类问题真的好用 更新:hdu的数据弱的真实,我交上去错的代价也对了.. 下面的代码是错的 /* 每个点的贡献度=权值*在这个点之前的 ...
- [zoj4046][树状数组求逆序(强化版)]
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4046 题意:有一个含有n个元素的数列p,每个元素均不同且为1~n中的一个, ...
- poj 2299 Ultra-QuickSort(树状数组)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 67681 Accepted: 25345 ...
随机推荐
- MySQL数据库引擎简介
简单说,当你访问数据库时,不管是手工访问,还是程序访问,都不是直接读写数据库文件,而是通过数据库引擎去访问数据库文件.以关系型数据库为例,你发SQL语句给数据库引擎,数据库引擎解释SQL语句,提取出你 ...
- IDEA创建Maven项目一直显示正在加载的问题
在用idea创建maven项目的时候 有时候会出现下面这种情况 出现原因 IDEA根据maven archetype的本质,其实是执行mvn archetype:generate命令,该命令执行时,需 ...
- 1-1+zookeeper简介
zookeeper是中间件,可以为分布式系统提供协调服务.如果没有分布式系统,zookeeper也发挥不了它的优势.
- 【总结整理】webGIS学习
安装ArcGIS Server + ArcSDE + PostgreSQL + ArcMap安装(windows7)博客:https://blog.csdn.net/buqutianya/articl ...
- gym - 101673I Twenty Four, Again (表达式树枚举)
题意及思路 模拟场上用一般方法枚举非常麻烦,一个小时没写出来,还是自己太菜了...用表达式树枚举有一个好处,判断需不需要加括号非常方便,只有当前节点运算符的优先级高于子节点的时候,才需要给子节点加一个 ...
- IP地址及子网掩码计算
主机号全0表示网络号,主机号全1表示广播地址 我们都知道,IP是由四段数字组成,在此,我们先来了解一下3类常用的IP A类IP段 0.0.0.0 到127.255.255.255 B类IP段 128. ...
- vimrc 我的专属vim配置
set nu set wrap syntax on filetype on "打开vim文件类型自动检测功能 set autoindent set smartindent set ruler ...
- java全栈day08--面向对象
今日内容介绍1.面向对象思想2.类与对象的二者关系3.局部变量和成员变量之间的关系4.封装的思想5.private,this关键字的用途6.案例 01面向对象和面向过程的思想 * A: 面向过程与面向 ...
- C# 中窗口AutoScaleMode属性
C# 窗体中有一个AutoScaleMode 这个属性,我们大家可能用的比较少. 它的作用是:当屏幕分辨率或字体发生改变时,窗体和控件是如何发生变化的.
- Python-第三方库requests详解(附requests中文官方教程)
转自http://blog.csdn.net/cyjs1988/article/details/73294774 Python+requests中文官方教程: http://www.python-re ...