[代码] 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\n", ans);
return 0;
}