Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 70674   Accepted: 26538

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 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

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

Source

 
题目意思:
对于给定的无序数组
求除经过多少次相邻的元素交换之后,可以使得数组升序
就是求一个数列的逆序数
 
 
方法一:
树状数组求解逆序数
从头到尾读入这些数,每读入一个数就更新树状数组,
查看它前面比它小的已出现过的有多少个数sum,
然后用当前位置减去该sum,
就可以得到当前数导致的逆序对数了。
把所有的加起来就是总的逆序对数。
code:
#include<queue>
#include<set>
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define max_v 500005
int n;
struct node
{
int v;
int pos;
} p[max_v];
int c[max_v];
int re[max_v];
int maxx;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int d)
{
while(x<=n)
{
c[x]+=d;
x+=lowbit(x);
}
}
int getsum(int x)
{
int res=;
while(x>)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
bool cmp(node a,node b)
{
return a.v<b.v;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==)
break;
memset(c,,sizeof(c));
for(int i=;i<=n;i++)
{
scanf("%d",&p[i].v);
p[i].pos=i;
} sort(p+,p++n,cmp);
for(int i=;i<=n;i++)
{
re[p[i].pos]=i;//离散化
} long long ans=;
for(int i=;i<=n;i++)
{
update(re[i],);
ans+=(i-getsum(re[i]));//当前位置减去前面比它小的数的个数之和就是答案
}
printf("%lld\n",ans);
}
return ;
}
/*
题目意思:
对于给定的无序数组
求除经过多少次相邻的元素交换之后,可以使得数组升序
就是求一个数列的逆序数 从头到尾读入这些数,每读入一个数就更新树状数组,
查看它前面比它小的已出现过的有多少个数sum,
然后用当前位置减去该sum,
就可以得到当前数导致的逆序对数了。
把所有的加起来就是总的逆序对数。
*/

感觉自己的树状数组这样写真的是傻的一批,离散化写的麻烦了,照着别人的离散化写的!

现在明白了离散化是什么东西:就是数据范围压缩!!!

贴一个自己离散化的代码

#include<queue>
#include<set>
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define max_v 500005
int n;
struct node
{
int v;
int pos;
} p[max_v];
int c[max_v];
int re[max_v];
int maxx;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int d)
{
while(x<max_v)
{
c[x]+=d;
x+=lowbit(x);
}
}
int getsum(int x)//返回1到x中小与等于x的数量
{
int res=;
while(x>)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
bool cmp(node a,node b)
{
if(a.v!=b.v)
return a.v<b.v;
else
return a.pos<b.pos;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==)
break;
memset(c,,sizeof(c));
for(int i=;i<=n;i++)
{
scanf("%d",&p[i].v);
p[i].pos=i;
} sort(p+,p++n,cmp); long long ans=;
for(int i=;i<=n;i++)
{
ans+=(i-getsum(p[i].pos)-);//先找再更新,避免getsum的时候算上自己
update(p[i].pos,);
}
printf("%lld\n",ans);
}
return ;
}

方法二:归并排序求解逆序数

在归并排序的过程中,比较关键的是通过递归,
将两个已经排好序的数组合并,
此时,若a[i] > a[j],则i到m之间的数都大于a[j],
合并时a[j]插到了a[i]之前,此时也就产生的m-i+1个逆序数,
而小于等于的情况并不会产生。

code:

#include<stdio.h>
#include<memory>
#define max_v 500005
typedef long long LL;
LL a[max_v];
LL temp[max_v];
LL ans;
void mer(int s,int m,int t)
{
int i=s;
int j=m+;
int k=s;
while(i<=m&&j<=t)
{
if(a[i]<=a[j])
{
temp[k++]=a[i++];
}else
{
ans+=j-k;//求逆序数
temp[k++]=a[j++];
}
}
while(i<=m)
{
temp[k++]=a[i++];
}
while(j<=t)
{
temp[k++]=a[j++];
}
}
void cop(int s,int t)
{
for(int i=s;i<=t;i++)
a[i]=temp[i];
}
int megsort(int s,int t)
{
if(s<t)
{
int m=(s+t)/;
megsort(s,m);
megsort(m+,t);
mer(s,m,t);
cop(s,t);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==)
break;
ans=;
for(int i=;i<n;i++)
scanf("%lld",&a[i]);
megsort(,n-);
printf("%lld\n",ans);
}
return ;
}
/*
题目意思:
对于给定的无序数组
求除经过多少次相邻的元素交换之后,可以使得数组升序
就是求一个数列的逆序数 在归并排序的过程中,比较关键的是通过递归,
将两个已经排好序的数组合并,
此时,若a[i] > a[j],则i到m之间的数都大于a[j],
合并时a[j]插到了a[i]之前,此时也就产生的m-i+1个逆序数,
而小于等于的情况并不会产生。
*/
 

POJ 2299 Ultra-QuickSort 求逆序数 (归并或者数状数组)此题为树状数组入门题!!!的更多相关文章

  1. poj 2299 Ultra-QuickSort (归并排序 求逆序数)

    题目:http://poj.org/problem?id=2299 这个题目实际就是求逆序数,注意 long long 上白书上的模板 #include <iostream> #inclu ...

  2. poj 2299 Ultra-QuickSort 归并排序求逆序数对

    题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题 ...

  3. Poj 2299 Ultra-QuickSort(归并排序求逆序数)

    一.题意 给定数组,求交换几次相邻元素能是数组有序. 二.题解 刚开始以为是水题,心想这不就是简单的冒泡排序么.但是毫无疑问地超时了,因为题目中n<500000,而冒泡排序总的平均时间复杂度为, ...

  4. nyoj 117 求逆序数 (归并(merge)排序)

    求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...

  5. poj 2299 Ultra-QuickSort(求逆序对)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 52778   Accepted: 19348 ...

  6. POJ训练计划2299_Ultra-QuickSort(归并排序求逆序数)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 39279   Accepted: 14163 ...

  7. POJ 2299 Ultra-QuickSort 归并排序、二叉排序树,求逆序数

    题目链接: http://poj.org/problem?id=2299 题意就是求冒泡排序的交换次数,显然直接冒泡会超时,所以需要高效的方法求逆序数. 利用归并排序求解,内存和耗时都比较少, 但是有 ...

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

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

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

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

随机推荐

  1. 一步一步实现web程序信息管理系统之三----登陆业务逻辑实现(验证码功能+参数获取)

    本篇紧接着上一篇文章[一步一步实现web程序信息管理系统之二----后台框架实现跳转登陆页面] 验证码功能 一般验证码功能实现方式为,前端界面访问一个url请求,后端服务代码生成一个图片流返回至浏览器 ...

  2. codechef Many Lists(树状数组 set)

    题意 题目链接 Sol 直接做肯定不好搞(反正我不会..) 直接开\(n\)个Pair类型的set,维护每个数的出现位置 每次在set中二分后暴力合并即可 然后就是树状数组的基本操作了 时间复杂度:\ ...

  3. css 关闭按钮实现

    通过css的伪元素:before,:after以及transform: rotate(45deg);旋转来实现(支持IE9及其以上版本) <div class="close" ...

  4. KaTeX.js

    KaTeX.js 官网:https://khan.github.io/KaTeX/

  5. Oracle spool 小结

    关于SPOOL(SPOOL是SQLPLUS的命令,不是SQL语法里面的东西.) 对于SPOOL数据的SQL,最好要自己定义格式,以方便程序直接导入,SQL语句如: select taskindex|| ...

  6. Azure 虚拟机上的 SQL Server 常见问题

    本主题提供有关运行 Azure 虚拟机中的 SQL Server 时出现的一些最常见问题的解答. 如果本文未解决你的 Azure 问题,请访问 MSDN 和 CSDN 上的 Azure 论坛. 你可以 ...

  7. 用适配器模式处理复杂的UITableView中cell的业务逻辑

    用适配器模式处理复杂的UITableView中cell的业务逻辑 适配器是用来隔离数据源对cell布局影响而使用的,cell只接受适配器的数据,而不会与外部数据源进行交互. 源码: ModelCell ...

  8. miniblast_hash算法c语言实现

    对于一组基因文件中的基因序列,选取一段基因片段,作为索引,利用hash表,查找固定的基因片段.有一定的并且容忍错误. 简单讲就是自己实现一个hashtable,将选出特定字符串建立索引,便于查询.输出 ...

  9. python 反转字符串 [::-1]的问题

    >>> a = '12345' >>> a[:-1]'1234' -1表示最后一个,所以取第一个到最后且不包含最后一个 >>> a[1:4:2]' ...

  10. openresty及lua的随机函数

    我们都知道,所谓的随机都是伪随机,随机的结果是由随机算法和随机种子决定的. 所以,当我们没有初始化的时候,如果直接使用math.random(),那么出来的值肯定是每次都一样,因为种子等于0. 因此, ...