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个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...
随机推荐
- CentOS7设置开机自启动命令大全
任务 旧指令 新指令 使某服务自动启动 chkconfig --level 3 httpd on systemctl enable httpd.service 使某服务不自 ...
- 二分求幂,快速求解a的b次幂
一个引子 如何求得a的b次幂呢,那还不简单,一个for循环就可以实现! void main(void) { int a, b; ; cin >> a >> b; ; i < ...
- php将汉字转换为拼音和得到词语首字母(三)
<?php function getfirstchar($s0){ $fchar = ord($s0{0}); if($fchar >= ord("A") and $f ...
- [转]Git学习笔记与IntelliJ IDEA整合
Git学习笔记与IntelliJ IDEA整合 一.Git学习笔记(基于Github) 1.安装和配置Git 下载地址:http://git-scm.com/downloads Git简要使用说明:h ...
- c++ ifstream
1.判断文件是否打开if(a.fail())if(!a.good())if(!a)上面3个等价 但上面的无法检测到 : 以不合适的文件模式打开文件失败a.is_open()可以检测到这个错误 所以推荐 ...
- Jmeter在命令行运行技巧
For non-interactive testing, you may choose to run JMeter without the GUI. To do so, use the followi ...
- javascript与 ios通讯解决办法
阔别1年半之久,一个JavaScript和ios通讯的想法终于被实现了(我不知道别人有没有早就实现过~). 记得早期ios内嵌html做通讯时,貌似做好的办法只能是 ios通过url来截取页面发送消息 ...
- opencv移植到ubuntu
原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/ OpenCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake ...
- SQLServer------聚集索引和非聚集索引的区别
转载: http://www.cnblogs.com/flashicp/archive/2007/05/08/739245.html 建立非聚集索引(vid不是主键) create index idx ...
- help()
help() 用于查看函数或模块的帮助信息 In [1]: help(id) # 查看id()这个函数的帮助信息,注意不要写成help(id()) id(...) id(object) -> i ...