使用BIT(Binary Indexed Tree)求数组里的逆序对

给定一个整数数组A,如果对于

i != j && i < j && A[i] > A[j]

就称i和j为一个逆序对。使用分治思想改写归并排序算法是最容易理解的O(nlog(n))的求逆序对的算法。使用BIT也可以达到O(nlog(n)),但是难以理解一些。先把代码贴在这里:

const int MAX_N = 1000;
int bit[MAX_N + 1], n;

int sum(int i) {
	int s = 0;
	while (i > 0) {
		s += bit[i];
		i -= i & -i;
	}
	return s;
}

void add(int i, int x) {
	while (i <= n) {
		bit[i] += x;
		i += i & -i;
	}
}

int a[4] = { 3, 2, 1, 4 };
void solve() {
	ll ans = 0;
	for (int j = 0; j < n; j++) {
		ans += j - sum(a[j]);
		add(a[j], 1);
	}
	cout << ans << endl;
}

对于BIT不了解的读者可以找一本书先了解一下,这里的代码来自于《挑战程序设计竞赛》。我们这里仅仅解释为什么main函数里的逻辑可以求得逆序对。首先我们看到在for循环结束前a[j]加了一,那么如果数组A完全是顺序排列的,我们可以预料到下一次循环,sum(a[1])的结果应该为一。但是如果出现了一个逆序对,我们会发现a[1]的值仍然为零,这时j-sum(a[j])的值就是j之前的逆序对的数量。所以for循环之后我们就得到了位置0,1,...,n-1之前的所有逆序对的和,就是答案。但是我们发现如果我们的数组不是1,2,...,n取值的,我们必须先进行处理。比如[5, 6, 2, 8],要被normalize成为[3,2,1,4]才可以。但是使用归并排序的算法计算逆序对是不需要normalize的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值