[代码] codevs 4163 hzwer 与 逆序对(树状数组)

- 传送门 -

 http://codevs.cn/problem/4163/
 

4163 hzwer与逆序对

时间限制: 1 s

空间限制: 256000 KB

题目等级 : 黄金 Gold

题目描述 Description

hzwer在研究逆序对。

对于数列{a},如果有序数对(I,j)满足:i<j,a[i]>a[j],则(i,j)是一对逆序对。

给定一个数列{a},求逆序对个数。

输入数据较大,请使用scanf代替cin读入。

*为防卡评测,时限调低至1s

输入描述 Input Description

第一行一个数n,表示{a}有n个元素。

接下来n个数,描述{a}。

输出描述 Output Description

一个数,表示逆序对个数。

样例输入 Sample Input

5
3 1 5 2 4

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

对于10%数据,1<=n<=100.

对于20%数据,1<=n<=10000.

对于30%数据,1<=n<=100000.

对于100%数据,1<=n<=1000000,1<=a[i]<=10^8.

tips:我没有想故意卡你们时限。一点这样的意思都没有。你们不要听风就是雨……
 

- 代码 -

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int M = 1e6 + 5;

int a[M], b[M];
ll sum[M];
int n, cnt;
ll ans;

int lowbit(int x) {
	return x&(-x);
}

int Bay(int x) {
	int l = 1, r = cnt;
	while (l <= r) {
		int mid = l + r >> 1;
		if (b[mid] == x) return mid;
		if (b[mid] < x) l = mid + 1;
		else r = mid - 1;
	}
}

void Add(int x) {
	while (x <= cnt) {
		sum[x] += 1;
		x += lowbit(x);
	}
}

ll Quy(int x) {
	ll ans = 0;
	while (x) {
		ans += sum[x];
		x -= lowbit(x);
	}
	return ans;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]), b[i] = a[i];
	sort(b+1, b+n+1);
	cnt = 1;
	for (int i = 2; i <= n; ++i)
		if (b[i] != b[i-1]) b[++cnt] = b[i];
	for (int i = 1; i <= n; ++i) {
		int k = Bay(a[i]);
		k = cnt + 1 - k;
		ans += Quy(k - 1);
		Add(k);
	}
	printf("%lld
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Anding-16/p/7300770.html