POJ 2299 Ultra-QuickSort 求逆序数 (归并或者数状数组)此题为树状数组入门题!!!
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 70674 | Accepted: 26538 |
Description

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
Output
Sample Input
5
9
1
0
5
4
3
1
2
3
0
Sample Output
6
0
Source
对于给定的无序数组
求除经过多少次相邻的元素交换之后,可以使得数组升序
就是求一个数列的逆序数
查看它前面比它小的已出现过的有多少个数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<=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 求逆序数 (归并或者数状数组)此题为树状数组入门题!!!的更多相关文章
- poj 2299 Ultra-QuickSort (归并排序 求逆序数)
题目:http://poj.org/problem?id=2299 这个题目实际就是求逆序数,注意 long long 上白书上的模板 #include <iostream> #inclu ...
- poj 2299 Ultra-QuickSort 归并排序求逆序数对
题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题 ...
- Poj 2299 Ultra-QuickSort(归并排序求逆序数)
一.题意 给定数组,求交换几次相邻元素能是数组有序. 二.题解 刚开始以为是水题,心想这不就是简单的冒泡排序么.但是毫无疑问地超时了,因为题目中n<500000,而冒泡排序总的平均时间复杂度为, ...
- nyoj 117 求逆序数 (归并(merge)排序)
求逆序数 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...
- poj 2299 Ultra-QuickSort(求逆序对)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 52778 Accepted: 19348 ...
- POJ训练计划2299_Ultra-QuickSort(归并排序求逆序数)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 39279 Accepted: 14163 ...
- POJ 2299 Ultra-QuickSort 归并排序、二叉排序树,求逆序数
题目链接: http://poj.org/problem?id=2299 题意就是求冒泡排序的交换次数,显然直接冒泡会超时,所以需要高效的方法求逆序数. 利用归并排序求解,内存和耗时都比较少, 但是有 ...
- 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个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...
随机推荐
- C# 简单的loading提示控件
自己画一个转圈圈的控件 using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...
- C#语言总结1
C#C#定义: C#是一门面向对象.面向组件的一门语言,是.NET的一部分. 程序结构: 命名空间 类{ 属性 方法 main函数入口 } 数据类型: C#的数据类型分为:值类型(Value type ...
- HEOI2017 游记
你若安好,便是晴天. …… 人就像命运下的蝼蚁,谁也无法操控自己的人生. ——阮行止 …… Day 0 中午就要出发了,上午教练还搞了一场欢乐信心赛,然而还是挂惨了.T3是bzoj的原题,但是当时写的 ...
- 03.CSS动画-->自定义动画
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 用CSS3 & jQuery创建apple TV海报视差效果
用CSS和jQuery来实现它,尽量看起来和原效果一样. 最终效果图 本教程里,我将使用CSS,HTML和jQuery来创建一个近似Apple TV视差效果,如果你正在阅读,我假设你对上述三种技术都有 ...
- drupal7 获取网站名称
$site_name=variable_get('site_name', 'Drupal');
- 移动目标在三维GIS中的实现方法
对于基于ArcGIS Runtime的应用程序,其实现方法比较简单,可以直接更新图形的Geometry属性,即可实现位置的移动: private void AddGraphics() { var gl ...
- MUI框架-07-HBuilder+夜神安卓模拟器
MUI框架-07-HBuilder+夜神安卓模拟器 有时候我们在 HBuilder 里面 web 浏览器预览我们的 MUI 项目界面时,总感觉这个 web 浏览器随便拖拉比例,大小可调,但它毕竟是浏览 ...
- flask代码统计作业
用户表: create table userInfo( id int not null unique auto_increment, name )not null, password ) not nu ...
- Spring3实战第一章 Aop 切面 XML配置
刚看spring3实战书籍第一章 切面以前没有关注过 现在看到了 随手试验一下 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Objec ...