您的位置:首页 > 其它

树状数组求逆序对

2016-08-07 11:11 344 查看

逆序对

题目描述给定一个数组A,它包含N个整数, 分别是A[1],A[2],...A
。如果存在下标i和j,使得 i < j 且 A[i]>A[j]同时成立,则(i,j)就为一个“逆序对”。
那么A数组总共有多少对不同的“逆序对”?输入格式 1247.in第一行为n(1≤n≤100000)。
接下来是n行,每行一个长整型范围内的整数。输出格式 1247.out一个整数,为逆序对的数目。输入样例 1247.in5
3
1
4
5
2输出样例 1247.out4

各测试点信息

测试点编号测试点分数测试点时限测试点内存
1101128
2101128
3101128
4101128
5101128
6101128
7101128
8101128
9101128
10101128
今天在石门中学的oj上练习了用树状数组求逆序对,其实方法跟昨天测试的第三题是一样的233用树状数组维护某个数出现的次数,即tree[i]表示i出现的次数,但这个数有可能很大啊。离散化一下就好咯。然后从左往右每个数扫一遍,对于Ai,它前面有(i-1)个数,而直接计算比Ai大的数的个数显然是比较麻烦的,不过两个数的大小关系不就大于、等于和小于三种嘛。我们可以方便的得出小于等于Ai的数的个数,再用(i-1)减去之即可。就这么简单。
//树状数组O(nlogn)求逆序对
//by LKB 2016.8.5
#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

#define lowbit(x) (x&(-x))

const int maxn = 1e5 + 9;

struct Tnode {
int x, y;
Tnode() {
x = y = 0;
}
} a[maxn]; //离散化时用

int n;
int b[maxn]; //离散后的数组
int tree[maxn]; //树状数组

bool cmp(Tnode i, Tnode j) {
return i.x < j.x;
}

void update(int k) { //单点修改
while(k <= n) {
++tree[k];
k += lowbit(k);
}
}

int query(int k) { //区间求和
int sum = 0;

while(k) {
sum += tree[k];
k -= lowbit(k);
}

return sum;
}

int main() {
freopen("1247.in", "r", stdin);
freopen("1247.out", "w", stdout);
cin >> n;

for(int i = 1; i <= n; i++) {
cin >> a[i].x;
a[i].y = i - 1;
}

//离散化
sort(a + 1, a + n + 1, cmp);
int now = 0;

for(int i = 1; i <= n; i++) {
if(i == 0 || a[i].x != a[i - 1].x) ++now;

b[a[i].y] = now;
}

long long ans = 0; //注意答案最多可能是n平方级的,要开long long

for(int i = 0; i < n; i++) {
ans += (i - query(b[i])); //求在自己的前面有多少比自己大的数
update(b[i]); //维护树状数组,加入当前值
}

cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: