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 ...
随机推荐
- Reporting services
“数据库引擎服务”可以承载报表服务器数据库.Reporting Services 需要SQL Server 2008 数据库引擎的本地或远程实例来承载报表服务器数据库.如果同时安装数据库引擎实例和 R ...
- 在异步回调中调用MessageBox.Show
public static void Test() { ThreadStart aThreadStart = delegate() { ); MessageBox.Show("Good!&q ...
- div+css学习笔记一(转)
div+css学习笔记一 (2011-05-12 07:32:08) 标签: div css 居中 背景图片 ie6 ie7 margin 杂谈 分类: 网页制作 1.IE6中用了float之后导致m ...
- Codeforces 914C Travelling Salesman and Special Numbers (数位DP)
题意:题目中定义了一种运算,把数字x变成数字x的二进制位数.问小于n的恰好k次运算可以变成1的数的个数(题目中的n是二进制数,n最大到2^1000) 思路:容易发现,无论多么大的数,只要进行了一次运算 ...
- 无人驾驶——4.控制之MPC模型预测控制
源自:<无人驾驶无人驾驶车辆模型预测控制>——龚建伟 参考:https://wenku.baidu.com/view/8e4633d519e8b8f67c1cb9fa.html 0.车辆模 ...
- Bootstrap 的 Dropdown
一.简介 Dropdown 就是下拉列表,这里 有一个例子. Dropdown 的完整代码如下: <div id="dropdownWrapper"> <butt ...
- WebGoat系列实验Injection Flaws
WebGoat系列实验Injection Flaws Numeric SQL Injection 下列表单允许用户查看天气信息,尝试注入SQL语句显示所有天气信息. 选择一个位置的天气,如Columb ...
- WebGoat系列实验Cross-Site Scripting (XSS)
WebGoat系列实验Cross-Site Scripting (XSS) PhishingTitle 本次实验是在一个已知存在XSS漏洞的页面进行钓鱼攻击.通过使用XSS与HTML注入,在页面中注入 ...
- Spring Bean的装配
Bean 的装配,即Bean对象的创建.容器根据代码要求创建Bean对象后再传递给代码的过程,称为Bean的装配. 一.默认分的装配方式 默认的装配的方式调用Bean类的构造方法 二.动态工厂Bean ...
- jmeter测试报告汉化及脚本编写
在做接口自动化时,生成的测试报告页面是英文的,如现在我们优化成汉文.操作如下: 1,下载汉化包 下载路径:https://i.cnblogs.com/Files.aspx?order=1 2,解压汉化 ...