当前位置: 首页 > news >正文

树状数组浅谈

【树状数组,就是这么简单!】https://www.bilibili.com/video/BV12a411i7rP?vd_source=e583d26dc0028b3e6ea220aadf5bc7fe

视频内容

树状数组1

问题1:如何构造树状数组?

首先我们假设树状数组已经构造好了(假设是c数组),考虑给第x个数加上k的函数怎么写

void add(int x,int k){//第x个数加kint tmp = x;while(x <= n){c[x] += k;x = x + lowbit(x);} }

给第x个数加k,要给c[x]和c[x]的全部后继都加上k,所以利用while循环,找到c[x]的全部后继,都加上k。

那么构造的时候,每读入一个元素a[i],也进行这个操作。相当于这个位置原本是0,加上了a[i]

for(int i = 1;i <= n;i ++){cin >> a[i];//构造树状数组 int tmp = i;while(tmp <= n){c[tmp] += a[i];tmp = tmp + lowbit(tmp);//后继 }}

当然,也可以直接利用add函数add(i,a[i])。

问题2,如何求区间和[x,y]

先找r前驱,把所有的前驱都加起来,是前y项的和;同理求出前x-1项的和,两者相减就是区间和了

int sum(int x,int y){//先求前缀和sum[y],再求sum[x - 1],相减即可int sumy = 0,sumx = 0;while(y){//找前驱 sumy += c[y];y = y - lowbit(y);}x = x - 1;while(x){sumx += c[x];x = x - lowbit(x);}return sumy - sumx;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
int lowbit(int i){return i&(-i);
}
int a[1100000];
int c[1100000];//前驱c[i-lowbit(i)],后继c[i+lowbit(i)] 
int n,m;
void add(int x,int k); 
int sum(int x,int y);
int main(void){//sum[7] = c[7] + c[6] + c[4];//int n,m;cin >> n >> m;//n个数据,m组操作 for(int i = 1;i <= n;i ++){cin >> a[i];//构造树状数组 int tmp = i;while(tmp <= n){c[tmp] += a[i];tmp = tmp + lowbit(tmp);//后继 }}while(m --){int a,b,c;cin >> a >> b >> c;if(a == 1){//addadd(b,c);}else{cout << sum(b,c) << endl;}}}
void add(int x,int k){//第x个数加kint tmp = x;while(x <= n){c[x] += k;x = x + lowbit(x);} }int sum(int x,int y){//先求前缀和sum[y],再求sum[x - 1],相减即可int sumy = 0,sumx = 0;while(y){//找前驱 sumy += c[y];y = y - lowbit(y);}x = x - 1;while(x){sumx += c[x];x = x - lowbit(x);}return sumy - sumx;
}

树状数组2

由于线段树一般只能解决单点修改(修改某一个元素的值)和区间查询(求某个区间的和),而本题需要对区间修改和单点查询,因此构造原来数组的树状数组是不行的

方法:首先构建原来数组的差分数组,再对差分数组构造树状数组,由于操作1是给[x,y]的每个元素都加k,对于差分数组来说只需要改变第x个元素的值和第y+1个元素的值,相当于单点修改。操作2是输出某个数x的值,对于差分数组来说是前x项和,也就是区间查询(求区间和),这样就可以利用树状数组解决此题辣!

#include<bits/stdc++.h>
using namespace std;
int b[500003],c[500003];
int n,m;
int lowbit(int x){return x&(-x);
}
void add(int i,int k); 
int sum(int x);
int main(void){cin >> n >> m;int x,y = 0;for(int i = 1;i <= n;i ++){cin >> x;b[i] = x - y;//add(i,b[i]);//第i个数加上b[i] y = x;}while(m --){int op;cin >> op;if(op == 1){int x,y,k;cin >> x >> y >> k;add(x,k);add(y + 1,-k);}else{int x;cin >> x;cout << sum(x) << endl;}}}
void add(int i,int k){int tmp = i;while(tmp <= n){c[tmp] += k;tmp = tmp + lowbit(tmp);}
}int sum(int x){//求差分数组的前x项和 int tmp = x,result = 0;while(tmp){result += c[tmp];tmp = tmp - lowbit(tmp);}return result;
}

代码的差分数组和差分的树状数组一起构建,没有开辟空间给原来数组(因为不需要)。


http://www.mrgr.cn/news/67780.html

相关文章:

  • 吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.11
  • SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
  • 递归-最大公约数(辗转相除法)
  • 【docker】5. 背景知识(了解)
  • ReactPress系列—Next.js 的动态路由使用介绍
  • ubuntu 异常 断电 日志 查看
  • 论文阅读:基于语义分割的非结构化田间道路场景识别
  • 100种算法【Python版】第55篇——Delaunay三角剖分之Bowyer-Watson算法
  • SSH实验3拒绝root用户远程登录
  • 2024.11.6:艾灸
  • hdmi介绍及DRM实现
  • 《现代网络技术》读书笔记:需求和技术
  • 年入百万:从初中辍学到 50 万读者!
  • audacity 保存中文文件保存报错问题解决
  • C++ OpenCV 理想滤波
  • opencv各个模块的概念说明
  • 人工智能:革新医疗、企业与日常生活的未来
  • 【Qt问题】解决 Cannot retrieve debugging output
  • 如何写研究的结论与讨论部分
  • 大模型开发企业智能小助手应用上篇
  • React中类组件和函数组件的理解和区别
  • C++ 标准模板库 (STL)- 学习推荐
  • 火语言RPA流程组件介绍--指纹浏览器管理
  • 2024 软件著作权申请详细操作过程
  • 如何下载无水印的TikTok视频
  • 【LeetCode】返回链表的中间结点、删除链表的倒数第 N 个结点