当前位置:   article > 正文

高级数据结构:树状数组以及逆序对求解_逆序对 与 树状数组

逆序对 与 树状数组

树状数组基础知识

树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于数组的单点修改&&区间求和.

另外一个拥有类似功能的是线段树.

具体区别和联系如下:

  1. 两者在复杂度上同级, 但是树状数组的常数明显优于线段树, 其编程复杂度也远小于线段树.
  2. 树状数组的作用被线段树完全涵盖, 凡是可以使用树状数组解决的问题, 使用线段树一定可以解决, 但是线段树能够解决的问题树状数组未必能够解决.
  3. 树状数组的突出特点是其编程的极端简洁性, 使用lowbit技术可以在很短的几步操作中完成树状数组的核心操作,其代码效率远高于线段树。

lowbit操作讲解

在这里插入图片描述

下面是二进制版本,能看到
更新过程是每次加了个二进制的低位1(101+1 ->110, 110 + 10 -> 1000, 1000 + 1000 -> 10000)
查询过程每次就是去掉了二进制中的低位1(1111 - 1 -> 1110, 1110 - 10 -> 1100, 1100 - 100 -> 1000)
讲解具体实施步骤
lowbit(x)是取出x的最低位1;具体代码为:

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

我们知道,对于一个数的负数就等于对这个数取反+1
以二进制数11010为例:11010的补码为00101,加1后为00110,两者相与便是最低位的1
其实很好理解,补码和原码必然相反,所以原码有0的部位补码全是1,补码再+1之后由于进位那么最末尾的1和原码
最右边的1一定是同一个位置(当遇到第一个1的时候补码此位为0,由于前面会进一位,所以此位会变为1)
所以我们只需要进行a&(-a)就可以取出最低位的1了
会了lowbit,我们就可以进行区间查询和单点更新了!!!

单点更新

此时如果我们要更改A[1],则有以下需要进行同步更新!!!
在这里插入图片描述

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

区间查询

举个例子 :
i=5
C[4]=A[1]+A[2]+A[3]+A[4];
C[5]=A[5];
可以推出: sum(i = 5) ==> C[4]+C[5];
序号写为二进制: sum(101)=C[(100)]+C[(101)];
第一次101,减去最低位的1就是100;
其实也就是单点更新的逆操作

int getsum(int x){
    int ans = 0;
    for(int i=x;i;i-=lowbit(i))
        ans += c[i];
    return ans;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

树状数组应用之逆序对

原理

我们想一想,树状数组能够解决哪些问题,求某个区间的数的和,我们能不能将求逆序对的问题向这个方向转化呢?
我们在换一种角度来看看逆序对:对于每一个数,可能和前面的数形成逆序对,也可能与后面的数形成逆序对。那我们化简一下,对每个数来说,我们只考虑其作为逆序对中第二个数的逆序对,然后将这样的逆序对加起来,实际上就是总逆序对个数。为什么呢,因为每个逆序对有两个元素,第一个数,第二个数。我们将逆序对的第二个数的情况都考虑完了,实际上已经考虑完了所有的逆序对。

题目及代码

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
const ll maxm=1e8+10;
ll n;
ll a[maxm],b[maxm];
ll ans=0;
ll lowbit(ll x){
    return x&(-x);
}
void update(ll x,ll val){
    for(ll i=x;i<=ans;i+=lowbit(i)){
        b[i]+=val;
        //cout<<i<<endl;
    }
}
ll getsum(ll x){
    ll res=0;
    for(ll i=x;i;i-=lowbit(i)){
        res+=b[i];
    }
    return res;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        ans=max(ans,a[i]);
    }
    ll cnt=0;
    for(int i=1;i<=n;i++){
        update(a[i],1);
        cnt+=i-getsum(a[i]);
        //cout<<i<<endl;
    }
    cout<<cnt;
	return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

推荐给大家的一段话


“遇事不决可问春风,春风不语即随本心”的意思是:对一件事犹豫不决,就问春风该如何做,春风给不出答案,就凭自己本心做出决断。“遇事不决可问春风,春风不语即随本心”一句出自网络作家“烽火戏诸侯”的《剑来》,其原文是:“遇事不决,可问春风。春风不语,遵循己心”。

在这里插入图片描述


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/654183
推荐阅读
相关标签
  

闽ICP备14008679号