题意 : 给出一个数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 (树状数组 && 离散化&&逆序)的更多相关文章

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

    题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...

  2. poj 2299 Ultra-QuickSort(树状数组求逆序数)

    链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...

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

    http://poj.org/problem?id=2299 题意:给出一组数,求逆序对. 思路: 这道题可以用树状数组解决,但是在此之前,需要对数据进行一下预处理. 这道题目的数据可以大到999,9 ...

  4. POJ - 2299 Ultra-QuickSort 【树状数组+离散化】

    题目链接 http://poj.org/problem?id=2299 题意 给出一个序列 求出 这个序列要排成有序序列 至少要经过多少次交换 思路 求逆序对的过程 但是因为数据范围比较大 到 999 ...

  5. POJ 2299 Ultra-QuickSort【树状数组 ,逆序数】

    题意:给出一组数,然后求它的逆序数 先把这组数离散化,大概就是编上号的意思--- 然后利用树状数组求出每个数前面有多少个数比它小,再通过这个数的位置,就可以求出前面有多少个数比它大了 这一篇讲得很详细 ...

  6. Ultra-QuickSort(树状数组求逆序对数)

    Ultra-QuickSort 题目链接:http://poj.org/problem?id=2299 Time Limit: 7000MS   Memory Limit: 65536K Total ...

  7. hdu2838树状数组解逆序

    离散化和排序后的序号问题搞得我实在是头痛 不过树状数组解逆序和偏序一类问题真的好用 更新:hdu的数据弱的真实,我交上去错的代价也对了.. 下面的代码是错的 /* 每个点的贡献度=权值*在这个点之前的 ...

  8. [zoj4046][树状数组求逆序(强化版)]

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4046 题意:有一个含有n个元素的数列p,每个元素均不同且为1~n中的一个, ...

  9. poj 2299 Ultra-QuickSort(树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 67681   Accepted: 25345 ...

随机推荐

  1. MySQL数据库引擎简介

    简单说,当你访问数据库时,不管是手工访问,还是程序访问,都不是直接读写数据库文件,而是通过数据库引擎去访问数据库文件.以关系型数据库为例,你发SQL语句给数据库引擎,数据库引擎解释SQL语句,提取出你 ...

  2. IDEA创建Maven项目一直显示正在加载的问题

    在用idea创建maven项目的时候 有时候会出现下面这种情况 出现原因 IDEA根据maven archetype的本质,其实是执行mvn archetype:generate命令,该命令执行时,需 ...

  3. 1-1+zookeeper简介

     zookeeper是中间件,可以为分布式系统提供协调服务.如果没有分布式系统,zookeeper也发挥不了它的优势.

  4. 【总结整理】webGIS学习

    安装ArcGIS Server + ArcSDE + PostgreSQL + ArcMap安装(windows7)博客:https://blog.csdn.net/buqutianya/articl ...

  5. gym - 101673I Twenty Four, Again (表达式树枚举)

    题意及思路 模拟场上用一般方法枚举非常麻烦,一个小时没写出来,还是自己太菜了...用表达式树枚举有一个好处,判断需不需要加括号非常方便,只有当前节点运算符的优先级高于子节点的时候,才需要给子节点加一个 ...

  6. IP地址及子网掩码计算

    主机号全0表示网络号,主机号全1表示广播地址 我们都知道,IP是由四段数字组成,在此,我们先来了解一下3类常用的IP A类IP段 0.0.0.0 到127.255.255.255 B类IP段 128. ...

  7. vimrc 我的专属vim配置

    set nu set wrap syntax on filetype on "打开vim文件类型自动检测功能 set autoindent set smartindent set ruler ...

  8. java全栈day08--面向对象

    今日内容介绍1.面向对象思想2.类与对象的二者关系3.局部变量和成员变量之间的关系4.封装的思想5.private,this关键字的用途6.案例 01面向对象和面向过程的思想 * A: 面向过程与面向 ...

  9. C# 中窗口AutoScaleMode属性

    C# 窗体中有一个AutoScaleMode 这个属性,我们大家可能用的比较少. 它的作用是:当屏幕分辨率或字体发生改变时,窗体和控件是如何发生变化的.

  10. Python-第三方库requests详解(附requests中文官方教程)

    转自http://blog.csdn.net/cyjs1988/article/details/73294774 Python+requests中文官方教程: http://www.python-re ...