树状数组——求逆序对个数(初学者都能看懂)

在网上翻看了一些博客,感觉大体对于树状数组求逆序对的讲解不够详细,那些博客,更多像是给已经学会逆序对的人复习用的。而初学者,可能要冥思苦想。接下来,我便从一个初学者的角度,来一步步的,讲解一下由树状数组求逆序对。需要的前置知识只有,会线段数组的基本应用。单点更新,区间查询,求lowbit。
先贴树状数组的基本代码。
求lowbit

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

单点更新

void update(int x,int y,int n){
    for(int i=x;i<=n;i+=lowbit(i))    //x为更新的位置,y为更新时增加的数,n为数组最大值
        c[i] += y;
}

区间查询

int getsum(int x){
    int ans = 0;
    for(int i=x;i;i-=lowbit(i))
        ans += c[i];
    return ans;
}

下面开始正题
逆序对的原理:在一组数中,如果ia[j],则这就是一组逆序对。
我们一般求逆序对的方法,对于每一个数,求出在它后面的且比它小的数。
代码如下:

int ans=0;
for(int i=1;i<=n;i++)
{
	for(int j=i+1;j<=n;j++)
	{
		if(ap[i]>ap[j])ans++;
	}
}

时间复杂度明显是n^2的,那能不能有更快的方法呢,就是用树状数组啦。
我们想一想,树状数组能够解决哪些问题,求某个区间的数的和,我们能不能将求逆序对的问题向这个方向转化呢?

我们在换一种角度来看看逆序对:对于每一个数,可能和前面的数形成逆序对,也可能与后面的数形成逆序对。那我们化简一下,对每个数来说,我们只考虑其作为逆序对中第二个数的逆序对,然后将这样的逆序对加起来,实际上就是总逆序对个数。为什么呢,因为每个逆序对有两个元素,第一个数,第二个数。我们将逆序对的第二个数的情况都考虑完了,实际上已经考虑完了所有的逆序对。

所以怎么把它转化为树状数组的问题呢。
还是举个例子吧:比如该数组为 5 3 4 2 1 7
刚开始先插入5,单点更新5这个位置+1,然后查询区间1到4的数,则逆序对加0个:1-0-1=0(第i个插入-该数前面的数-本身)这个数是在它前面插入并且在它右边的数,没错,这就是以该数为第二个数的逆序对了,在它前面插入的数才会在该数进行计算的时候包含在内。
完整来一遍
插入5,逆序对加(1-0-1)。
插入3,逆序对加(2-0-1)。
插入4,逆序对加(3-1-1)。
插入2,逆序对加(4-0-1)。
插入1,逆序对加(5-0-1)。
插入7,逆序对加(6-5-1)。
代码如下。

单点更新

void update(int x,int n){
    for(int i=x;i<=n;i+=lowbit(i))    //x为更新的位置n为数组最大值
        c[i] ++;
}

区间查询

int getsum(int x){
    int ans = 0;
    for(int i=x;i;i-=lowbit(i))
        ans += c[i];
    return ans;
}

综合代码

//原数组 
int ap[maxn+1]={0};
//树状数组 
int c[maxn+1]={0};
int ans=0;
for(int i=1;i<=n;i++)
{
	scanf("%d",&ap[i]);
	update(ap[i],n);
	ans+=(i-getsum(ap[i]-1)-1);
}

这样的时间复杂度就是nlgn的。
但是,是不是有些问题,如果按照一般来说的话,如果要求数仅小于10^9,那难道还开这么大的数组吗,肯定爆了,那怎么办?
术语好像是离散化,我们说白一点,就是用更简单的数来表示相对大小。
比如1234 1526 128783 121 2343 23423432
我们可以用2 3 5 1 4 6来代替相对大小,求得的逆序对个数不变。
当然,这样的时间复杂度过高。还有一种方法,就是用结构体将(1234,跟数组下标1合起来),其他几个数也是,然后对1234 1526 128783 121 2343 23423432进行排序,可以发现得到的次关键字 4 1 2 5 3 6,你会发现它的逆序对个数和原数1234 1526 128783 121 2343 23423432一样。为什么,你看看:
1234 1526 128783 121 2343 23423432
1 2 3 4 5 6
猜测1:当上面数组中任意两个数交换时,逆序对减少多少个,下面的数就加上多少个逆序对。所有上面逆序对加下面逆序对等于定值。
猜测2:对称性,对上面排序得到下面,对下面排序得到上面。
1234 1526 128783 121 2343 23423432
1 2 3 4 5 6
排序得到
121 1234 1526 2343 128783 23423432
4 1 2 5 3 6。
进行相对变换
1 2 3 4 5 6
2343 121 1234 128783 1526 23423432。
没推出来,等以后有实力了再补,希望大家能评论帮助。

你可能感兴趣的:(树状数组——求逆序对个数(初学者都能看懂))