Ultra-QuickSort---poj2299 (归并排序.逆序数.树状数组.离散化)
题目链接:http://poj.org/problem?id=2299
题意就是求把数组按从小到大的顺序排列,每次只能交换相邻的两个数, 求至少交换了几次
就是求逆序数
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 501000
using namespace std;
int a[N], b[N];
__int64 cnt; void Merge(int r, int mid, int l)
{
int i = r, j = mid+, k = ;
while(i<=mid && j<=l)
{
if(a[i] > a[j])
{
b[k++] = a[j++];
cnt += mid-i+; ///说明下标从i到mid的值都比a[j]大所以逆序数要+mid-i+1;
}
else if(a[i] < a[j])
{
b[k++] = a[i++];
}
else
{
b[k++] = a[i++];
j++;
}
}
while(i<=mid)
b[k++] = a[i++];
while(j<=l)
b[k++] = a[j++];
for(i=; i<k; i++)///将有序的临时数组 元素 刷回 被排序的数组 a 中,
a[i+r] = b[i];
} void MergeSort(int r, int l)
{
int mid = (r+l)/;
if(r < l)
{
MergeSort(r, mid);///对前半部分进行排序
MergeSort(mid + , l);///对后半部分进行排序
Merge(r, mid, l);/// 合并前后两部分
}
}
int main()
{
int n;
while(scanf("%d", &n),n)
{
cnt = ;
for(int i=; i<n; i++)
scanf("%d", &a[i]);
MergeSort(, n-);
printf("%I64d\n", cnt);
}
return ;
}
归并排序
用树状数组
序列3 5 4 8 2 6 9
大体思路为:新建一个数组,将数组中每个元素置0
0 0 0 0 0 0 0
取数列中最大的元素,将该元素所在位置置1 统计该位置前放置元素的个数,为0
0 0 0 0 0 0 1
接着放第二大元素8,将第四个位置置1 统计该位置前放置元素的个数,为0
0 0 0 1 0 0 1
继续放第三大元素6,将第六个位置置1 统计该位置前放置元素的个数,为1
0 0 0 1 0 1 1
…
这样直到把最小元素放完,累加每次放元素是该元素前边已放元素的个数,这样就算出总的逆序数来了在统计和计算每次放某个元素时,该元素前边已放元素的个数时如果一个一个地数,那么一趟复杂度为O(n),总共操
作n趟,复杂度为O(n^2),然而复杂度太大,
当然,在每次统计的过程中用树状数组可以把每一趟计数个数的复杂度降为O(logn),这样整个复杂度就变为O(nlogn)
树状数组是一种很好的数据结构,这有一篇专门描述树状数组的文章
将序列中的每个数按照从大到小的顺序插入到树状数组中,给当前插入节点及其到根节点之间的这条路径上的每个数加1,然后统计该节点右边放置元素的个数
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 501000
#define met(a, b) memset(a, b, sizeof(a)) int Hash[N], n;
__int64 Tree[N]; struct node
{
int V, id;
///重载运算符中:<是从大到小,>是从小到大;
friend bool operator < (node a, node b)
{
return a.V < b.V;
}
}a[N]; int lowbit(int x)
{
return x&(-x);
} void Update(int pos, int num)
{
while(pos<=n)
{
Tree[pos] += num;
pos += lowbit(pos);
}
} __int64 GetSum(int pos)
{
__int64 s=;
while(pos)
{
s += Tree[pos];
pos -= lowbit(pos);
}
return s;
} int main()
{
while(scanf("%d", &n), n)
{
met(a,); met(Tree, ); met(Hash, );
for(int i=; i<=n; i++)
{
scanf("%d", &a[i].V);
a[i].id = i;
} sort(a+, a+n+);///按V从大到小排序;
for(int i=; i<=n; i++)
Hash[a[i].id] = i;///离散化后的Hash数组大小关系顺序和输入的数组大小关系一样; __int64 ans=;
for(int i=; i<=n; i++)
{
int pos = Hash[i];
Update(pos, );///每插入一个数时,就把那个位置置为1;
int m = GetSum(pos);///从第一个元素到第pos个元素的和,即m=前pos个元素中小于pos的个数;
ans += i-m;///所以逆序数应该加上比pos个元素大的,即总个数-比pos小的;
}
printf("%I64d\n", ans);
}
return ;
}
树状数组
也可以用线段树来写,每次更新pos点,然后在求1-pos的和即可
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <string>
typedef long long LL;
#define INF 0x3f3f3f3f
#define met(a, b) memset(a, b, sizeof(a))
#define N 500005 using namespace std; #define Lson r<<1
#define Rson r<<1|1 struct node
{
int L, R;
LL sum;
int Mid(){return (L+R)/;}
}a[N*]; struct Num
{
int num, pos;
friend bool operator < (Num p, Num q)
{
return p.num > q.num;
}
}b[N]; void Build(int r, int L, int R)
{
a[r].L = L; a[r].R = R; if(L == R) return; Build(Lson, L, a[r].Mid());
Build(Rson, a[r].Mid()+, R);
} void Update(int r, int pos, int num)
{
if(a[r].L == pos && a[r].R == pos)
{
a[r].sum += num;
return ;
} if(pos > a[r].Mid())
Update(Rson, pos, num);
else if(pos <= a[r].Mid())
Update(Lson, pos, num); a[r].sum = a[Lson].sum + a[Rson].sum;
} LL Query(int r, int L, int R)
{
if(L > R) return ; if(a[r].L == L && a[r].R == R)
return a[r].sum; if(R <= a[r].Mid())
return Query(Lson, L, R);
else if(L > a[r].Mid())
return Query(Rson, L, R);
else
{
LL ans1 = Query(Lson, L, a[r].Mid());
LL ans2 = Query(Rson, a[r].Mid()+, R);
return ans1 + ans2;
}
} int main()
{
int n;
while(scanf("%d", &n), n)
{
met(a, );
met(b, ); for(int i=; i<=n; i++)
{
scanf("%d", &b[i].num);
b[i].pos = i;
} Build(, , n); sort(b+, b+n+); LL ans = ;
for(int i=; i<=n; i++)
{
Update(, b[i].pos, );
ans += Query(, , b[i].pos-);
}
printf("%I64d\n", ans);
}
return ;
}
线段树
Ultra-QuickSort---poj2299 (归并排序.逆序数.树状数组.离散化)的更多相关文章
- POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...
- ACM学习历程—HDU5592 ZYB's Premutation(逆序数 && 树状数组 && 二分)(BestCoder Round #65 1003)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5592 题目大意就是给了每个[1, i]区间逆序对的个数,要求复原原序列. 比赛的时候2B了一发. 首先 ...
- cdoj 841 休生伤杜景死惊开 逆序数/树状数组
休生伤杜景死惊开 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 陆伯言军陷八卦 ...
- P1908 逆序对——树状数组&离散化&快读快写の学习
题目简述: 对于给定的一段正整数序列,逆序对就是序列中 a_i>a_jai>aj 且 i<ji<j 的有序对. 输出序列中逆序对的数目. 知识补充: 树状数组: 这东西就是 ...
- hdu 1394 Minimum Inversion Number 逆序数/树状数组
Minimum Inversion Number Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showprob ...
- zoj 3157 Weapon 逆序数/树状数组
B - Weapon Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Submit Sta ...
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- POJ 2299 【树状数组 离散化】
题目链接:POJ 2299 Ultra-QuickSort Description In this problem, you have to analyze a particular sorting ...
- BZOJ_5055_膜法师_树状数组+离散化
BZOJ_5055_膜法师_树状数组+离散化 Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...
随机推荐
- Spring定时器Quartz的用法
首先导入需要的两个jar: spring-context-support-4.1.1.RELEASE.jar quartz-2.2.1.jar 1.创建两个类: 2. QuartzConfigurat ...
- c++ double float 数值比较
浮点数在内存中的存储机制和整型数不同,其有舍入误差,在计算机中用近似表示任意某个实数.具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于基 ...
- UIView的背景渐变
//绘制背景渐变 /* CGCradientCreateWithColorComponents函数需要四个参数: 色彩空间:(Color Space)这是一个色彩范围的容器,类型必须是CGColorS ...
- [转]JVM性能调优监控工具
http://my.oschina.net/feichexia/blog/196575?p=1#comments JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jCo ...
- java导出word文件
java导出word文件 test5.ftl文件生存方法, 第一步:用word新建test5.doc,填写完整模板,将需导出数据用${}代替 第二步:将test5.doc另存为test5.xml 第三 ...
- 如何使用ChemDraw绘制自由基符号
ChemDraw软件是一款全球领先的化学绘图工具,能够绘制各种复杂的化学符号和化学结构图形.ChemDraw汉化版结合了中国用户的使用习惯,可以帮助国内化学行业工作者更加轻松快捷地绘制化学图形.本教程 ...
- Node.js 原生模块开发方式变迁
https://mp.weixin.qq.com/s/-oLqB8ITk_Q5AIoNLzBg0w
- MySql阶段案例
MySql阶段案例 案例一 涉及的知识点:数据库和表的基本操作,添加数据,多表操作 题目 使用sql语句请按照要求完成如下操作: (1)创建一个名称为test的数据库. (2)在test数据库中创建两 ...
- kafka原理
今天因为工作接触kafka,先说说kafka是干嘛的. kafka: 说简单点他就是一个基于分布式的消息发布-订阅系统. 然后再理解一些专有名词: Kafka 专用术语 Broker:Kafka 集群 ...
- Nginx.conf 配置文件详细说明
在此记录下Nginx服务器nginx.conf的配置文件说明, 部分注释收集与网络. #运行用户user www-data; #启动进程,通常设置成和cpu的数量相等worker_process ...