题目:

冒泡排序的交换次数

给定一个1~n的排列a,..,an-,求对这个数列进行冒泡排序所需要的交换次数(冒泡排序是每次找到满足a>a+t的i,并交换a;和a++t,直到这样的i不存在为止的算法)。

限制条件

●1≤n≤100000

输入


n=4,a={3,1,4,2}


输出


3


分析:

冒泡排序的复杂度是O(n^2),所以无法通过模拟冒泡排序的过程来计算需要的交换次数。不过我们可以通过选取适当的数据结构来解决这个问题。

首先,所求的交换次数等价于满足i<j, ai>aj的(i,j)数对的个数(这种数对的个数叫做逆序数)。而对于每一个j, 如果能够快速求出满足i,<j,ai>aj 的i的个数,那么问题就能迎刃而解。我们构建一个值的范围是1~n的BIT,按照j=0, 1, 2, . n-1的顺序进行如下操作。

■把j-(BIT查 询得到的前aj项的和)加到答案中

■把BIT中aj位置上的值加1

对于每一个j, (BIT查询得到的前aj项的和)就是满足i<j, ai>aj的I 的个数。因此把这个值从j中减去之后,得到的就是满足i<j, ai>aj,的的个数。由于对于每一个j的复 杂度是0(logn),所以整个算法的复杂度是O(n log n)。

实现:

#include<iostream>
#include<vector>
using namespace std;
int n;
const int maxn = 1e9;
vector<int>bit(maxn);
void add(int i,int x) {
	while(i<maxn) {
		bit[i]+=x;
		i+=i&-i;
	}
}
int sum(int i) {
	int ans=0;
	while(i>0) {
		ans+=bit[i];
		i-=i&-i;
	}
	return ans;
}
int main() {
	cin>>n;
	int res=0;
	for(int i=0; i<n; ++i) {
		int t;
		cin>>t;
		res+=i-sum(t);
		add(t,1);
	}
	cout<<res;
	return 0;
}