POJ 2299 Ultra-QuickSort(求逆序数)
来源:互联网 发布:cst软件价格 编辑:程序博客网 时间:2024/05/18 03:02
题目链接:
http://poj.org/problem?id=2299
解题思路:
树状数组实际上就是一个数组,只不过它的每个元素保存的是跟原来数组的一些元素相关的结合值。
若A为原数组,定义数组C为树状数组。C数组中元素C[ i ]表示A[ i –lowbit( i ) + 1]至A[ i ]的结合值。
lowbit(i)是i的二进制中最后一个不为零的位数的2次方,可以这样计算 lowbit(i)=x&(-x)
当想要查询一个sum(n)时,可以依据如下算法即可:
step1: 令sum = 0,转第二步;
step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;
step3: 令n = n – lowbit(n),转第二步。
n = n – lowbit(n)这一步实际上等价于将n的二进制的最后一个1减去。而n的二进制里最多有log(n)个1,所以查询效率是log(n)的。
修改一个节点,必须修改其所有祖先,最坏情况下为修改第一个元素,最多有log(n)的祖先。所以修改算法如下(给某个结点i加上x):
step1: 当i > n时,算法结束,否则转第二步;
step2: Ci = Ci + x, i = i + lowbit(i)转第一步。
i = i +lowbit(i)这个过程实际上也只是一个把末尾1补为0的过程。
求逆序的思路:
可以把数一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 i- getsum( data[i] ),其中 i 为当前已经插入的数的个数, getsum( data[i] )为比data[i] 小的数的个数,i- getsum( data[i] ) 即比 data[i] 大的个数, 即逆序的个数。最后需要把所有逆序数求和,就是在插入的过程中边插入边求和。
AC代码(树状数组):
#include <iostream>#include <cstdio>#include <algorithm>using namespace std;typedef long long ll;const int N = 500005;int n;struct node{ int pos,val;}no[N];int reflect[N];int c[N];bool cmp(const node &a,const node &b){ return a.val < b.val;}int lowbit(int x){ return x&(-x);}void update(int x){ while(x <= n){ c[x] += 1; x += lowbit(x); }}int sum(int x){ int ans = 0; while(x){ ans += c[x]; x -= lowbit(x); } return ans;}int main(){ while(scanf("%d",&n),n){ for(int i = 1; i <= n; i++){ scanf("%d",&no[i].val); no[i].pos = i; } sort(no+1,no+n+1,cmp); for(int i = 1; i <= n; i++) reflect[no[i].pos] = i;//离散化 for(int i = 1; i <= n; i++) c[i] = 0;//初始化 ll ans = 0; for(int i = 1; i <= n; i++){ update(reflect[i]); ans += (ll)(i - sum(reflect[i])); } printf("%lld\n",ans); } return 0;}
归并排序是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为 若干个子序列,每个子序列是有序的,然后再把有序的子序列合并为整体有序序列 。
归并排序是分治算法的一个典型的应用,而且是稳定的一种排序,可以利用归并排序的过程中,计算每个小区间的逆序数,进而得到大区间的逆序数。那么,问题就解决了。
AC代码(归并排序):
#include <iostream>#include <cstdio>#include <algorithm>#define INF 0xfffffffusing namespace std;typedef long long ll;const int N = 500005;int n;int a[N],L[N],R[N];ll ans;void Merge(int a[],int l,int mid,int r){ int n1 = mid-l+1; int n2 = r-mid; int i,j,k; for(i = 1; i <= n1; i++) L[i] = a[l+i-1]; for(i = 1; i <= n2 ;i++) R[i] = a[mid+i]; L[n1+1] = INF; R[n2+1] = INF; i = 1; j = 1; for(k = l; k <= r; k++) { if(L[i] <= R[j]) { a[k] = L[i]; i++; } else { a[k] = R[j]; j++; ans += (ll)(n1-i+1); } }}void Merge_sort(int a[],int l,int r){ if(l < r) { int mid = (l+r)>>1; Merge_sort(a,l,mid); Merge_sort(a,mid+1,r); Merge(a,l,mid,r); }}int main(){ while(scanf("%d",&n),n){ for(int i = 1; i <= n; i++) scanf("%d",&a[i]); ans = 0; Merge_sort(a,1,n); printf("%lld\n",ans); } return 0;}
- POJ 2299 Ultra-QuickSort (求逆序数)
- POJ 2299 Ultra-QuickSort(归并排序求逆序数)
- poj 2299 Ultra-QuickSort(树状数组 / 求逆序数)
- 2299 Poj Ultra-QuickSort(归并排序求逆序数)
- POJ 2299 Ultra-QuickSort(求逆序数)
- POJ 2299 Ultra-QuickSort(求逆序数)
- POJ 2299 Ultra-QuickSort(树状数组求逆序数)
- poj 2299 Ultra-QuickSort(求逆序数 )
- POJ 2299-Ultra-QuickSort(树状数组求逆序数)
- (POJ 2299)Ultra-QuickSort 归并排序求逆序数
- POJ 2299 Ultra-QuickSort(逆序数)
- poj 2299 Ultra-QuickSort(归并排序求逆序数)
- poj 2299 Ultra-QuickSort(求逆序数,树状数组)
- poj 2299 Ultra-QuickSort 求逆序数 树状数组解法
- Ultra-QuickSort poj 2299--树状数组求逆序数
- Poj 2299 Ultra-QuickSort(归并排序求逆序数)
- poj 2299 Ultra-QuickSort :归并排序求逆序数
- POJ 2299 Ultra-QuickSort 分治法求逆序数
- Hibernate——Hql实例+详解
- 关于pkg: /data/local/tmp/com.example.zy.deyijia Failure [INSTALL_FAILED_OLDER_SD问题
- leetcode 151: Reverse Words in a String
- Mac下最好用的离线词典-欧陆词典破解版
- hdu 5109 Alexandra and A*B Problem
- POJ 2299 Ultra-QuickSort(求逆序数)
- Sorting It All Out
- 代写代做程序设计 国外算法编程 VB/C语言/C++/数据结构/Java/PHP/Python
- 关于support design包中behaviour的使用
- 知行合一
- 疯狂Java讲义中的程序,使用代理服务器来获取网上的资源
- 火狐访问博客园报400错误问题解决
- centos常用命令
- 棋盘移动最短路径问题(Dijkstra算法)