• lowbit和树状数组的理解与部分应用


    目录

    一、前言

    二、树状数组

    三、题例

    1、上链接

    2、基本思路

    3、代码

    (1)C++(AC)

    (2)python(7/10  有3个样例时间超限)


    一、前言

    对于学计算机的同学来说,学习算法是一件非常重要的事情,废话不多讲,我们来讲讲“树状数组问题”。

    二、树状数组

    相关问题:

    1、什么是树状数组
    顾名思义就是一个结构为树形结构的数组,与二叉树的结构类似但又不同,它是在二叉树的结构上删除了一些中间节点,来看下面这幅图就明白了。

    2、树状数组可以解决什么问题呢
    可以解决大部分区间上面的修改以及查询的问题,例如:

    ①单点修改,单点查询

    ②区间修改,单点查询

    ③区间查询,区间修改

    换言之,线段树能解决的问题,树状数组大部分也可以,但是并不一定都能解决,因为线段树的扩展性比树状数组要强。

    3、树状数组和线段树的区别在哪儿
    有人会问了既然线段树的问题能够用树状数组解决而且线段树还比树状数组扩展性强,那为什么不直接用线段树呢?问的很好,树状数组的作用就是为了简化线段树

    举个例子:一个问题可以用线段树解决写代码半个小时,但是用树状数组只需要10分钟,那么你会选择哪一个算法呢?没错,基于某些简单的问题,我们没必要用到功能性强但实现复杂的线段树(杀鸡焉用宰牛刀)。

    4、树状数组的优点
    优点:修改和查询操作复杂度于线段树一样都是logN,但是常数比线段树小,并且实现比线段树简单。

    缺点:扩展性弱,线段树能解决的问题,树状数组不一定能解决。

    5、前置知识—lowbit(x)运算
    如何计算一个非负整数n在二进制下的最低为1及其后面的0构成的数?

    所以,lowbit的值为n&-n。

    教学视频(讲得非常好!!!墙裂推荐!!!):〔manim | 算法 | 数据结构〕 完全理解并深入应用树状数组 | 支持多种动态维护区间操作_哔哩哔哩_bilibili

    (复习的时候去看我的算法笔记“树状数组”部分就行)

    三、题例

    1、上链接

    P3374 【模板】树状数组 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    2、基本思路

    常规套路树状数组。

    3、代码

    (1)C++(AC)

    1. #include
    2. using namespace std;
    3. int n,m;
    4. const int N=500009;
    5. int a[N],t[N]; //a是待输入的数组,t是树状数组,t[x]保存以x为根的子树中叶节点值的和
    6. void createTree(){ //构建树状维护数组 t
    7. for(int i=1;i<=n;i++){
    8. int j=i+(i&-i); //当前节点的父亲
    9. if(j1){
    10. t[j]+=t[i];
    11. }
    12. }
    13. }
    14. int lowbits(int x){ //lowbits
    15. return x&-x;
    16. }
    17. void add(int x,int k){
    18. for(;x<=n;x+=lowbits(x)) t[x]+=k;
    19. }
    20. int ask(int x){ //
    21. int ans=0;
    22. for(;x;x-=x&-x)
    23. ans+=t[x];
    24. return ans;
    25. }
    26. int main(){
    27. cin>>n>>m;
    28. for(int i=1;i<=n;++i){
    29. cin>>a[i];
    30. t[i]=a[i];
    31. }
    32. createTree();
    33. while(m--){
    34. int x,y,z;
    35. cin>>x>>y>>z;
    36. if(x==1){
    37. add(y,z);
    38. }else if(x==2){
    39. int ans=ask(z)-ask(y-1);
    40. cout<
    41. }else{
    42. cout<<"error"<
    43. }
    44. }
    45. return 0;
    46. }

    (2)python(7/10  有3个样例时间超限)

    1. n,m=map(int,input().split())
    2. a=[0]*500009 # a是待输入的数组
    3. t=[0]*500009 # t是树状数组,t[x]保存以x为根的子树中叶节点值的和
    4. def createTree(): # 构建树状维护数组 t
    5. global t
    6. for i in range(1,n+1):
    7. j=i+(i&-i) # 当前节点的父亲
    8. if j1:
    9. t[j]+=t[i]
    10. def lowbits(x)->int: # 没用的函数,只是说x的lowbits就是x&-x
    11. return x&-x
    12. def add(x,k):
    13. while(x<=n):
    14. t[x]+=k
    15. x+=x&-x
    16. def ask(x)->int:
    17. ans=0
    18. while(x>0):
    19. ans+=t[x]
    20. x-=x&-x
    21. return ans
    22. line=[0]+list(map(int,input().split()))
    23. for i in range(1,n+1):
    24. a[i]=line[i]
    25. t[i]=line[i]
    26. createTree()
    27. for _ in range(m):
    28. x,y,z=map(int,input().split())
    29. if x==1:
    30. add(y,z)
    31. elif x==2:
    32. ans=ask(z)-ask(y-1)
    33. print(ans)
    34. else:
    35. print("error")

    以上,树状数组

    祝好

     

  • 相关阅读:
    使用数据库实现缓存功能
    Linux中的进程程序替换
    100行代码自建Flutter状态管理库
    力扣(LeetCode)813. 最大平均值和的分组(C++)
    国庆创作周 组播《第十二课》
    【Zookeeper】——入门&本地安装
    Docker(三)、Dockerfile探究
    Grads:绘制风流畅
    03、主动信息收集
    数据库连接池之c3p0-0.9.1.2,16年的古董,发生连接泄露怎么查(二)
  • 原文地址:https://blog.csdn.net/m0_52711790/article/details/127591215