树状数组

一. 概述

树状数组是一种支持数组的单点修改,以及求前缀和(区间求和)的一种简单数据结构,作为线段树的下位替代
简单来说,树状数组就是利用lowbit(二进制化最后一位表示的值)的性质,把n个节点串起来,隐式地构造一棵树
每个节点x的父亲是x+lowbit(x),当前x节点左边最大的节点是x-lowbit(x)

正常来说单点修改时间复杂度为O(1),求区间和时间复杂度为O(n)
使用前缀和的时候单点修改O(n),区间求和O(1)

树状数组属于一种折中的方法,实际上是利用lowbit和二进制位的性质实现的一种简易区间划分(相比线段树)

二. C++做题模板

2.1 求左侧前缀和

    int n;//所有数的范围
    vector<int> tree;//初始化n+1的长度
    int lowbit(int x){//求二进制化最后一位的值
        return x&(-x);
    }
    void updata(int i,int k){ //在i位置加上k,O(logn)复杂度单点修改
        while(i<=n){//更新子树上所有值
            tree[i]+=k;
            i+=lowbit(i);//移动到父亲节点
        }
    }

    long long getsum(int i){  //求数组前i项的和
        long long res=0;
        while(i>0){//O(logn)求前缀和
            res+=tree[i];
            i-=lowbit(i);//移动到前一棵子树(子区间)
        }
        return res;
    }

2.2 求左侧最大值

    int lowbit(int x){//求二进制化最后一位的值
        return x&(-x);
    }
    void updata(int i,long long k){ //
        while(i<=idx){//更新子树上所有值
            tree[i] = max(tree[i],k);
            i+=lowbit(i);//移动到父亲节点
        }
    }

    long long getmax(int i){  //求数组前i项的和
        long long res = 0;//比0大才加上
        while(i>0){//O(logn)求前缀和
            res = max(res,tree[i]);
            i-=lowbit(i);//移动到前一棵子树(子区间)
        }
        return res;
    }

2.3 离散化

int idx = 1;
map<int,int> m;//离散化优先顺序
for(int i=0;i<n;i++)
    m[val[i]]++;
for(auto &[k,v]:m)
    v = idx++; //值离散化对应
for(auto &v:val)
    v = m[v];//用离散化值替换对应数值

三. 应用

1. 将数组清空

2. 数组中的逆序对

3. 统计包含每个点的矩形数目

4. 区间和的个数

5. 最大和查询

6. 平衡子序列的最大和

posted @ 2023-05-01 03:02  失控D大白兔  阅读(15)  评论(0编辑  收藏  举报