线段树
# 定义
线段树是常用来维护区间信息的数据结构。
线段树可以在的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。
# 实现
以数组 arr{9,3,-1,8,4,-2} 为例 (下标从 1 开始)
## 存储
//区间[L,R], w表示维护的数据, lazy为懒惰标记。
struct node
{
int L,R,w,lazy;
}tree[maxn];
## 建树

void build(int L,int R,int k)
{
tree[k].L=L; tree[k].R=R; tree[k].lazy=0;
if(tree[k].L==tree[k].R)
{
scanf("%d",&tree[k].w);
return;
}
int m=(L+R)/2;
build(L,m,k*2);
build(m+1,R,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
## 单点查询

void ask_point(int L,int R,int l,int r,int k)
{
if(tree[k].L==tree[k].R)
{
printf("%d",tree[k].w);
return ;
}
if(tree[k].lazy) down(k);
int m=(L+R)/2;
if(l<=m) ask_point(L,m,l,r,k*2);
else ask_point(m+1,R,l,r,k*2+1);
}
## 单点修改

void change_point(int L,int R,int l,int r,int k,int add)
{
if(tree[k].L==tree[k].R)
{
tree[k].w+=add;
return;
}
if(tree[k].lazy) down(k);
int m=(L+R)/2;
if(l<=m) change_point(L,m,l,r,k*2,add);
else change_point(m+1,R,l,r,k*2+1,add);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
## 区间查询

void ask_interval(int L,int R,int l,int r,int k,int &ans)
{
if(tree[k].L>=l&&tree[k].R<=r)
{
ans+=tree[k].w;
return;
}
if(tree[k].lazy) down(k);
int m=(L+R)/2;
if(l<=m) ask_interval(L,m,l,r,k*2,ans);
if(r>m) ask_interval(m+1,R,l,r,k*2+1,ans);
}
## 区间修改

void change_interval(int L,int R,int l,int r,int k,int add)
{
if(tree[k].L>=l&&tree[k].R<=r)
{
tree[k].w+=(tree[k].R-tree[k].L+1)*add;
tree[k].lazy+=add;
return;
}
if(tree[k].lazy) down(k);
int m=(L+R)/2;
if(l<=m) change_interval(L,m,l,r,k*2,add);
if(r>m) change_interval(m+1,R,l,r,k*2+1,add);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
## 下传函数
void down(int k)
{
tree[k*2].lazy+=tree[k].lazy;
tree[k*2+1].lazy+=tree[k].lazy;
tree[k*2].w+=tree[k].lazy*(tree[k*2].R-tree[k*2].L+1);
tree[k*2+1].w+=tree[k].lazy*(tree[k*2+1].R-tree[k*2+1].L+1);
tree[k].lazy=0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· 赶AI大潮:在VSCode中使用DeepSeek及近百种模型的极简方法
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地