逆序数

前言

  由于刚开始学习树状数组,觉得还是学的有些吃力,逆序数我也是花了好久才搞懂的,下面就写一些我的理解好了。

题意

  给你n个数,让你求这n个数的逆序数。

大概思路

  求逆序数就是求每个数前面比他大的数的个数(或者后面比它小的个数),直接暴力就是O(n^2),而用树状数组就是O(nlogn)。我们可以边插入更新边计和,我们用数组a[i]表示第i个数再n个数中的大小序号(第i个数是a[i]大的数),那么getsum(a[i])就是比a[i]小的数数量。由于我们是边插入边计数,所以在更新第i个数时,getsum(a[i])是第i个数左边比他小的个数和,那么i-getsum(a[i])就是前面比他大的数,一遍跑完就行。

例子

数组c即为树状数组.5个数100 120 23 65 40
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 0   0 0 0 0
 ans=0;

插入第一个数100后
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 0   0 0 1 0
 ans+=1-getsum(4);

第二个
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 0   0 0 1 1
 ans+=2-getsum(5);

第三个
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 1   1 0 2 1
 ans+=3-getsum(1);

第四个
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 1   1 1 3 1
 ans+=4-getsum(3);

第五个
    100 120 23 65 40
  a[i] 4   5 1 3 2
  c[i] 1   2 1 4 1
 ans+=5-getsum(2);
这就是大概的步骤

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<map>
#include<cstdio>
#include<string>
using namespace std;
int a[100009];
int  c[100009];
struct node
{
	int  val;
	int  ord;
}shu[100009];
bool cmp(node a, node b)
{
	return a.val < b.val;
}
int  n;
void update(int  x)
{
	for (int  i = x; i <= n; i += i & (-i))
	{
		c[i] += 1;
	}
}
int  getsum(int  x)
{
	int  ans = 0;
	while (x)
	{
		ans += c[x];
		x -= x & (-x);
	}
	return ans;
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> shu[i].val;
		shu[i].ord = i;
	}
	sort(shu + 1, shu + 1 + n, cmp);
	for (int i = 1; i <= n; i++)a[shu[i].ord] = i;//找到大小序号
	int  ans = 0;
	for (int i = 1; i <= n; i++)
	{
		update(a[i]);
		ans += i - getsum(a[i]);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2020-03-13 21:00  我是小怪兽  阅读(220)  评论(0)    收藏  举报