poj 2299 Ultra-QuickSort(数学:求逆序数||数据结构:树状数组)
2014-07-31 16:33
656 查看
求一个数组的逆序数
因为数据较大所以不能用冒泡排序
这里用到归并排序...到现在不看书还是写不出来
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/awkward.gif)
注意这里在归并排序过程中求逆序数个数的方法!
证明如下:
对于当前两个数组,a和b分别有序
合并a[i] b[j]的过程中我们这样考虑逆序数的个数:
如果a[i] > b[j],则a[i]后面的数必然都大于b[j],针对b[j]逆序数为a[i]后面数的个数,即len(a)-i+1
如果a[j] <= b[j], 则a[i]后面的数与b[j]的大小关系无法判断,我们只能接着判断a[i+1]和b[j]的关系
而针对b中每个元素的逆序数之和必然为总的逆序数
代码如下:
树状数组做法:
如输入val:9 1 0 5 4
则这五个数对应下标依次为pos:1 2 3 4 5
把输入的五个数联合下标进行排序得到:
val:0 1 4 5 9
pos:3 2 5 4 1
再令r[pos[i]] == i
此时有:
下标: 1
2 3
4 5
val: 0
1 4 5
9
r: 1
2 3 4
5//此时val和r中元素相对大小关系相同
pos: 3
2 5 4
1
得到:
下标i==r[pos[i]]:
1 2 3 4 5
pos: 3 2 5 4 1
可以发现此时r数组中的数值相对大小关系和val数组中相对大小关系相同
但是数值之间变得更加紧凑!这就使得我们缩小了所使用数组的范围,节省了空间;这叫做离散化操作
接下来我们只要找到r数组的逆序数即可
顺序访问r并执行树状数组add(r[i], 1)操作
则执行树状数组sum(r[i])返回小于等于r[i]的数的个数
i表示当前数组中插入的数的个数
则i-sum(r[i])即为1-i这些下标存放数中大于r[i]的数个数
代码如下:
因为数据较大所以不能用冒泡排序
这里用到归并排序...到现在不看书还是写不出来
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/awkward.gif)
注意这里在归并排序过程中求逆序数个数的方法!
证明如下:
对于当前两个数组,a和b分别有序
合并a[i] b[j]的过程中我们这样考虑逆序数的个数:
如果a[i] > b[j],则a[i]后面的数必然都大于b[j],针对b[j]逆序数为a[i]后面数的个数,即len(a)-i+1
如果a[j] <= b[j], 则a[i]后面的数与b[j]的大小关系无法判断,我们只能接着判断a[i+1]和b[j]的关系
而针对b中每个元素的逆序数之和必然为总的逆序数
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #define MAXN 500010 #define LL long long using namespace std; int a[MAXN],tmp[MAXN]; LL ans; void merge(int L, int R, int M) { int i, j, k = 1; for(i=L,j=M+1; i<=M&&j<=R; ) { if(a[i] < a[j]) { tmp[k++] = a[i++]; } else { tmp[k++] = a[j++]; ans += M-i+1; } } for( ; i<=M; ) tmp[k++] = a[i++]; for( ; j<=R; ) tmp[k++] = a[j++]; for(i=1; i<k; ++i) a[L+i-1] = tmp[i]; } void mergesort(int front, int end) { if(front < end) { mergesort(front, (front+end)/2); mergesort((front+end)/2+1, end); merge(front, end, (front+end)/2); } } int main(void) { int n; while(scanf("%d", &n) && n) { ans = 0; for(int i=1; i<=n; ++i) { cin >> a[i]; } mergesort(1, n); cout << ans << endl; } return 0; }
树状数组做法:
如输入val:9 1 0 5 4
则这五个数对应下标依次为pos:1 2 3 4 5
把输入的五个数联合下标进行排序得到:
val:0 1 4 5 9
pos:3 2 5 4 1
再令r[pos[i]] == i
此时有:
下标: 1
2 3
4 5
val: 0
1 4 5
9
r: 1
2 3 4
5//此时val和r中元素相对大小关系相同
pos: 3
2 5 4
1
得到:
下标i==r[pos[i]]:
1 2 3 4 5
pos: 3 2 5 4 1
可以发现此时r数组中的数值相对大小关系和val数组中相对大小关系相同
但是数值之间变得更加紧凑!这就使得我们缩小了所使用数组的范围,节省了空间;这叫做离散化操作
接下来我们只要找到r数组的逆序数即可
顺序访问r并执行树状数组add(r[i], 1)操作
则执行树状数组sum(r[i])返回小于等于r[i]的数的个数
i表示当前数组中插入的数的个数
则i-sum(r[i])即为1-i这些下标存放数中大于r[i]的数个数
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #define MAXN 500010 #define LL long long using namespace std; struct Node { int val, pos; }node[MAXN]; int r[MAXN],c[MAXN], n; LL ans; bool cmp(Node a, Node b) { return a.val < b.val; } int lowbit(int x) { return (-x)&x; } int sum(int x) { int sum = 0; while(x > 0) { sum += c[x]; x -= lowbit(x); } return sum; } void add(int x) { while(x <= n) { c[x]++; x += lowbit(x); } } int main(void) { while(scanf("%d", &n) && n) { ans = 0; for(int i=1; i<=n; ++i) { scanf("%d", &node[i].val); node[i].pos = i; } sort(node+1, node+n+1, cmp); for(int i=1; i<=n; ++i) { r[node[i].pos] = i; c[i] = 0; } for(int i=1; i<=n; ++i) { add(r[i]); printf("\n----------%d:\n", i); for(int j=1; j<=n; ++j) printf("%d\t", c[j]); printf("--------%d\n", i-sum(r[i])); ans += i-sum(r[i]); } cout << ans << endl; } return 0; }
相关文章推荐
- POJ 2299 Ultra-QuickSort(离散化+树状数组求逆序对)
- Ultra-QuickSort (poj 2299 归并排序 || 树状数组 求逆序对)
- POJ 题目2299 Ultra-QuickSort(树状数组求逆序对)
- POJ 2299 Ultra-QuickSort (树状数组求逆序数 || 线段树 +离散化)
- POJ 2299 Ultra-QuickSort 【树状数组求逆序数】
- poj2299 B - Ultra-QuickSort(线段树与树状数组求逆序对数)
- POJ 2299 Ultra-QuickSort 【树状数组 离散化 逆序对】
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- POJ2299 Ultra-QuickSort(树状数组求逆序数+离散化)
- poj 2299 Ultra-QuickSort 【线段树 or 线段树+lazy or 树状数组 or 归并排序】 求逆序对
- [树状数组 逆序对] 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 【归并排序求逆序数 OR 树状数组求逆序数】