poj 2299 Ultra-QuickSort(树状数组-改上求下+改下求上||归并排序)
来源:互联网 发布:微艾薇h5建站 编辑:程序博客网 时间:2024/06/06 11:04
Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536KTotal Submissions: 60497 Accepted: 22431
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.
Ultra-QuickSort produces the output
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
59105431230
Sample Output
60
归并排序,或用树状数组记录,先写树状数组
1:树状数组,对于题目来说 999,999,999的数据范围,开数组肯定要爆内存,由于n只有500000,可以对数据离散化一下,把每个数据改成1~n之间的数,拿第一组数据来说,9最大,9的角标为1,所以让a[1]=5;
先上个改上界,求下界的码,不太好看懂,感觉有点绕;
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define maxn 500010typedef long long LL;struct node{ int x,pos;}q[maxn];int a[maxn],num[maxn];int n;int lowbit(int x){ return x&-x;}bool cmp(node s,node b){ return s.x<b.x;}void add(int i,int x){ while(i<=n) { a[i]+=x; i+=lowbit(i); }}int getsum(int i){ int sum=0; while(i>0) { sum+=a[i]; i-=lowbit(i); } return sum;}int main(){ while(~scanf("%d",&n),n) { memset(a,0,sizeof(a));//注意清零 for(int i=1;i<=n;++i) { scanf("%d",&q[i].x); q[i].pos=i;//记录原始的位置 } sort(q+1,q+n+1,cmp); for(int i=1;i<=n;++i) num[q[i].pos]=i;//离散化 LL ans=0; for(int i=1;i<=n;++i) { ans+=(i-1)-getsum(num[i]);//前面有i-1个数,getsum(num[i])为小于num[i]的数 add(num[i],1);//加入数组中 } printf("%lld\n",ans); } return 0;}
下面是自己改的,改下界求上界的码,个人感觉很简洁
既然每次更新的是1~a[i]之间<=a[i]的个数,那么我读取的时候直接读a[i]~n不就是a[i]~n之间>=a[i]的值吗?
关于相等的情况:会有这样一个问题,读取的时候为什么不是a[i]~n之间>=a[i],那么如果出现两个值相等的情况呢?,我考虑了很久关于这个问题,其实没必要,假如出现几个数相等的情况,但经过离散化之后,他们所储存的值是不相等的,原本位置靠后的快排后位置相较于几个相等的值,它依然靠后,这就保证了一个值更新时不会影响后面和这个值相等的值的读取,举个例子:
比如有这样几个数 :1,2,5,5
离散后 a:1,2,3,4;
更新i=1,2时暂且不谈,
read求和是对a[i]~n;
i=3,ans+read(a[3]) 求和3~n 然后更新3,更新3时,更新的是1~3,也就是小于等于a[3]的
i=4,ans+read(a[4]) 求和4~n 然后更新4,会发现位置3和位置4都是5,但更新时并没有影响
至于add为什么放后面,因为最后一个数的逆序数一定是0,不需要读取,少读取一次
#include <iostream>#include <iomanip>#include<stdio.h>#include<string.h>#include<stack>#include<stdlib.h>#include<queue>#include<map>#include<math.h>#include<algorithm>#include<vector>#define mem(a,b) memset(a,b,sizeof(a))#define ll long long#define maxn 500005using namespace std;int n;struct node{ int val,pos;}e[maxn];int t[maxn],a[maxn];bool cmp(node a,node b){ return a.val<b.val;}int lowbit(int x){ return x&-x;}void add(int x,int num){ for(int i=x;i>0;i-=lowbit(i)) { t[i]+=num; }}int read(int x){ int sum=0; for(int i=x;i<=n;i+=lowbit(i)) sum+=t[i]; return sum;}int main(){ while(~scanf("%d",&n),n) { mem(t,0); for(int i=1;i<=n;i++) { scanf("%d",&e[i].val); e[i].pos=i; } sort(e+1,e+1+n,cmp); for(int i=1;i<=n;i++) a[e[i].pos]=i; ll ans=0; for(int i=1;i<=n;i++) { ans+=read(a[i]); //每次加上i~n之间小于a[i]的个数 add(a[i],1); //更新1~i之间<=a[i]的个数 } printf("%lld\n",ans); } return 0;}再敲一遍归并排序的模板
#include <iostream>#include <iomanip>#include<stdio.h>#include<string.h>#include<stack>#include<stdlib.h>#include<queue>#include<map>#include<math.h>#include<algorithm>#include<vector>#define mem(a,b) memset(a,b,sizeof(a))#define ll long long#define maxn 500005using namespace std;int a[maxn],c[maxn];ll cnt;void Merge(int a[],int first,int mid,int last,int c[]){ int i=first,j=mid+1; int m=mid,n=last; int k=0; while(i<=m||j<=n) { if(j>n||(i<=m&&a[i]<=a[j])) { c[k++]=a[i++]; } else { c[k++]=a[j++]; cnt+=(m-i+1); } } for(i=0;i<k;i++) a[first+i]=c[i];}void merge_sort(int a[],int first,int last,int c[]){ if(first<last) { int mid=(first+last)/2; merge_sort(a,first,mid,c); merge_sort(a,mid+1,last,c); Merge(a,first,mid,last,c); }}int main(){ int n; while(~scanf("%d",&n),n) { mem(c,0); cnt=0; for(int i=0;i<n;i++) scanf("%d",&a[i]); merge_sort(a,0,n-1,c); printf("%lld\n",cnt); } return 0;}
0 0
- poj 2299 Ultra-QuickSort(树状数组-改上求下+改下求上||归并排序)
- POJ:2299 Ultra-QuickSort(归并排序/树状数组)
- POJ 2299 Ultra-QuickSort 树状数组,归并排序
- POJ 2299 Ultra-QuickSort (树状数组、归并排序)
- POJ 2299 Ultra QuickSort <树状数组+离散化 / 归并排序>
- POJ Ultra-QuickSort 逆序数 树状数组 归并排序
- poj 2299 Ultra-QuickSort 求逆序对,树状数组和归并排序
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- POJ 2299 Ultra-QuickSort 求逆序对数(归并排序,树状数组)
- POJ 2299 Ultra-QuickSort(树状数组+离散化 或 归并排序求逆序)
- POJ 2299 Ultra-QuickSort 【归并排序求逆序数 OR 树状数组求逆序数】
- POJ 2299 Ultra-QuickSort【求逆序数:归并排序|树状数组】
- Ultra-QuickSort (poj 2299 归并排序 || 树状数组 求逆序对)
- POJ 2299 Ultra-QuickSort(归并排序·树状数组·逆序对)
- poj-2299-Ultra-QuickSort-归并排序求逆序数--或树状数组
- POJ 2299 Ultra-QuickSort(逆序对数,线段树/树状数组/归并排序)
- POJ 2299 Ultra-QuickSort(归并排序 || 树状数组 || 线段树)
- POJ 2299 Ultra-QuickSort(归并排序,树状数组,离散化)
- 我的世界史蒂夫---熊孩子版
- Java面试题集(三)
- 中国剩余定理
- JQuery基础
- 生成器
- poj 2299 Ultra-QuickSort(树状数组-改上求下+改下求上||归并排序)
- 算法训练:Ugly Number II
- OOAD实验三
- (OK) Lineage-14.1(Android 7)
- 安卓事件传递机制图解
- JQuery UI开发技巧
- 创建Maven工程(web项目)
- Unity编辑器中Status窗口详解
- Android N Setttings 零-壹 读源码------first part