POJ2299 Ultra-QuickSort 权值线段树 详细图解

这道题解法有很多种,归并排序、树状数组,权值线段树都可以做。这里介绍一下用权值线段树的解法。如果你还不了解线段树以及权值线段树的话,建议先去看一下相关内容。

题意

先来说下题意,这题意思在使用冒泡排序算法对数组进行排序时,需要交换多少次。其实也就是再求数组中逆序对的个数。

思路

首先对数组进行离散化操作后,依次插入到线段树中,并且算出当前树中比它大的值有多少个。最后累加起来即可。具体过程看下面的图解。

核心代码

  • 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;
}

猜你喜欢

转载自blog.csdn.net/qq_43058685/article/details/105442399
今日推荐