逆序数
前言
由于刚开始学习树状数组,觉得还是学的有些吃力,逆序数我也是花了好久才搞懂的,下面就写一些我的理解好了。
题意
给你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;
}

浙公网安备 33010602011771号