首页 > 代码库 > nyoj 117 求逆序数 【树状数组】+【离散化】

nyoj 117 求逆序数 【树状数组】+【离散化】

这道题的解法真的很好!!!


思路:建立一个结构体包含val和id, val就是输入的数,id表示输入的顺序。然后按照val从小到大排序,如果val相等,那么就按照id排序。

如果没有逆序的话,肯定id是跟i(表示拍好后的顺序)一直一样的,如果有逆序数,那么有的i和id是不一样的。所以,利用树状数组的特性,我们可以简单的算出逆序数的个数。

如果还是不明白的话举个例子。(输入4个数)

输入:9 -1 18 5

输出 3.

输入之后对应的结构体就会变成这样

val:9 -1 18 5

id:  1  2  3  4

排好序之后就变成了

val :  -1 5 9 18

id:      2 4  1  3

之后再利用树状数组的特性就可以解决问题了;


注意:id 要从1开始。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define M 1000005
using std::sort;
struct node{
	int id, val;
}s[M];
int c[M], n;
int cmp(node a, node b){
	if(a.val != b.val) return a.val < b.val;
	return a.id<b.id;
}

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

int getsum(int x){
	int sum = 0;
	while(x){
		sum += c[x];
		x -= lowbit(x);
	}
	return sum;
}

void add(int x){
	while(x <= M){
		c[x]++;
		x += lowbit(x);
	}
} 
int main(){
	int t, i;
	scanf("%d", &t);
	while(t --){
		scanf("%d", &n);
		for(i = 1; i<= n; i ++){
			scanf("%d", &s[i].val);
			s[i].id = i;
			//c[i] = 0;
		}
		memset(c, 0, sizeof(int)*(n+1));
		sort(s+1, s+n+1, cmp);
		long long ans = 0;
		for( i = 1; i <= n; i ++){
			add(s[i].id);  //和下面的不能互换
			ans += (i-getsum(s[i].id));  //这里是(i-getsum(s[i].id))
		}
		printf("%lld\n", ans);
	}
	return 0;
}        

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=117

nyoj 117 求逆序数 【树状数组】+【离散化】