这道题解法有很多种,归并排序、树状数组,权值线段树都可以做。这里介绍一下用权值线段树的解法。如果你还不了解线段树以及权值线段树的话,建议先去看一下相关内容。
题意
先来说下题意,这题意思在使用冒泡排序算法对数组进行排序时,需要交换多少次。其实也就是再求数组中逆序对的个数。
思路
首先对数组进行离散化操作后,依次插入到线段树中,并且算出当前树中比它大的值有多少个。最后累加起来即可。具体过程看下面的图解。
核心代码
res
:保存线段树中比当前值大的数的个数pos
:要插入的位置
void update(int rt, int l, int r, int pos,int &res) {
if (l == r) {
tree[rt]++;
return;
}
if (pos <= mid) {
update(lson, pos,res);
// 右子树中的节点一定是比当前数要大的。
res += tree[rt << 1 | 1];
}
else
update(rson,pos,res);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
图解
以样例为例:
9 | 0 | 0 | 5 | 4 | |
---|---|---|---|---|---|
插入后的位置 | 5 | 2 | 1 | 4 | 3 |
AC代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
const int maxn = 5e5 + 10;
int tree[maxn << 2], arr[maxn];
vector<int> vec;
int getId(int x) {
return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1;
}
void update(int rt, int l, int r, int pos,int &res) {
if (l == r) {
tree[rt]++;
return;
}
if (pos <= mid) {
update(lson, pos,res);
res += tree[rt << 1 | 1];
}
else
update(rson,pos,res);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
int main() {
ios::sync_with_stdio(false);
int n;
while (cin >> n && n) {
memset(arr, 0, sizeof(arr));
memset(tree, 0, sizeof(tree));
vec.clear();
int i;
for (i = 1; i <= n; i++) {
cin >> arr[i];
vec.push_back(arr[i]);
}
sort(vec.begin(), vec.end());
vec.erase( unique(vec.begin(), vec.end()),vec.end());
long long ans = 0;
for (i = 1; i <= n; i++) {
int id = getId(arr[i]);
int tmp = 0;
update(1, 1, n, id,tmp);
ans += tmp;
}
cout << ans << endl;
}
return 0;
}