您的位置:首页 > 理论基础 > 数据结构算法

poj 2299 Ultra-QuickSort(数学:求逆序数||数据结构:树状数组)

2014-07-31 16:33 656 查看
求一个数组的逆序数

因为数据较大所以不能用冒泡排序

这里用到归并排序...到现在不看书还是写不出来


注意这里在归并排序过程中求逆序数个数的方法!

证明如下:

对于当前两个数组,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: