尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

树状数组 线段树 笔记

树状数组  线段树 笔记
📅 发布时间:2026/6/24 5:58:58

写于 2023.11

树状数组

树状数组是维护 \(n\) 个数的前缀信息的一维数组。

其树型结构如下

这样的结构有着写法简单,常数小的特点。

其模板代码如下:

inline int lowbit(const int &x){//最后一个 '1' 对应的值 return x&-x;
}
void add(int pos,int val){//单点修改,将 a[pos] 的值增加 val while(pos<=n) t[pos]+=val,pos+=lowbit(pos);
}
int query(int pos){//查询[1,pos]的和 int sum=0;while(pos) sum+=t[pos],pos-=lowbit(pos);return sum;
}

除发挥其原本的前缀维护功能外( \(O(logn)\) 的前缀查询与单点修改),还可以用它来维护一个差分数组。这样,前缀和查询就变为了修改后的值的查询,弥补了差分数组只能“多次操作,一次查询”的短板。

将调用部分稍作修改即可完成 \(O(logn)\) 的区间修改与单点查询。

//此处t数组实际为一个差分数组
//[l,r]+val
add(l,val),add(r+1,-val);
//query: pos
printf("%d\n",query(pos));

其实,树状数组还可以方便地进行 \(O(logn)\) 的区间修改与前缀查询。

方法:对 query 与 add 函数进行修改,使其返回二次前缀和结果。

数学分析如下:

\[\begin{aligned} \sum^r_{i=l}\sum^i_{j=l} t_j &=\sum^r_{i=l}(r-i+1)\times t_i\\ &=\sum^r_{i=l}((r+1)\times t_i-i\times t_i)\\ &=(r+1)\times\sum^r_{i=l}t_i-\sum^r_{i=l}i\times t_i \end{aligned} \]

所以,我们可以维护两个树状数组,其意义分别为 \(t_i\) 与 \(i\times t_i\) 的前缀。

代码如下:

int t1[maxn],t2[maxn];//t1为t的前缀,t2为i*t的前缀 
inline int lowbit(const int &x){return x&-x;}
void add(int pos,int val){int tem=pos;while(pos<=n) t1[pos]+=val,t2[pos]+=tem*val,pos+=lowbit(pos);
}
int query(int pos){int sum=0,tem=pos;while(pos) sum+=(tem+1)*t1[pos]-t2[pos],pos-=lowbit(pos);return sum;
}
void add_array(int l,int r,int val){add(l,val),add(r+1,-val);}
int query_array(int l,int r){return query(r)-query(l-1);}

简单包装为 class 可以有效增加代码的可读性。

inline int lowbit(const int &x){return x&-x;
}
class BIT{private:ll t[maxn];public:void add(int pos,ll val){for(int i=pos;i<=n;i+=lowbit(i)) t[i]+=val;}ll query(int pos){ll sum=0;for(int i=pos;i;i-=lowbit(i)) sum+=t[i];return sum;}
}

线段树

1 当不需要区间修改的线段树题目的做法

线段树是维护一个区间的树形结构。其维护的信息需要具有可加性(即通过组成大区间的两个小区间可以得到大区间的值)。

维护的信息具有可减性或其他可以使用树状数组的情况应用树状数组代替以获得更高的效率。

线段树的模板

struct node{int l,r;//other imformations
} t[4*maxn]; 
void pushup(node &u,node &l,node &r){//using l & r to make the new u//eg.//	u.val=l.val+r.val;
}
void build(int u,int l,int r){t[u]={l,r};if(l==r){// do something} else {int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);pushup(t[u],t[u<<1],t[u<<1|1]);}
}
void modify(int u,int pos,int val){if(t[u].l==t[u].r){// do modify} else {int mid=t[u].l+t[u].r>>1;if(pos<=mid) modity(u<<1,pos,val);else modify(u<<1|1,pos,val);pushup(t[u],t[u<<1],t[u<<1|1]);}
}
node query(int u,int l,int r){if(t[u].l>=l&&t[u].r<=r) return t[u];int mid=t[u].l+t[u].r>>1;if(r<=mid) return query(u<<1,l,r);else if(l>mid) return query(u<<1|1,l,r);node ans,ansl=query(u<<1,l,r),ansr=query(u<<1|1,l,r);pushup(ans,ansl,ansr);return ans;
}

此处 pushup 意为通过传入的后两个参数更新第一个位置的值,需要根据维护的具体信息修改。

build 的注释部分意为叶子结点的信息赋值,modify 的注释部分意为叶子结点的信息修改。这些部分均需要根据维护的信息改变。

有时维护的信息比较简单,query 可以不返回一整个结点,视题目而定。

相关新闻

  • 大模型(LLM)基本原理
  • 实训(补)
  • 2025年下半年江苏网架、钢结构、光伏支架钢管、托辊钢管、汽车传动轴钢管厂家推荐指南:专业选择与权威解析

最新新闻

  • MATLAB算法思维进阶:从Cody挑战到数值计算实战
  • MATLAB Online云端统计可视化:从函数应用到协作工作流实战
  • MATLAB Web App中隐藏标签页的3种实战方案与避坑指南
  • 从Simulink到赛道:扭矩矢量控制算法开发与实车部署全流程解析
  • 深入解析PowerPC指令集:MPC850处理器编码格式与硬件实现原理
  • 深入解析SC140 DSP片上调试单元EOnCE:寄存器机制与实时数据交换实战

日新闻

  • 终极指南:如何用shadPS4在电脑上免费畅玩PS4游戏
  • 打造个性化Instagram Clone:主题定制与用户体验优化技巧
  • 未来展望:RoseTTAFold-All-Atom的发展路线图与社区支持资源汇总

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号