线段树

本文详细介绍线段树的基本概念、构建方法、更新与查询操作,并提供完整的C++实现代码。通过实例讲解如何使用线段树解决区间更新及查询问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接复制过来的效果太差了

还是移步去https://www.cnblogs.com/TenosDoIt/p/3453089.html

还有这个 https://www.cnblogs.com/ACworker/p/7703537.html

线段树从零开始,

https://blog.youkuaiyun.com/zearot/article/details/52280189 

超详细的模板哦

#include <bits/stdc++.h>
using namespace std;
/*定义*/
#define maxn 100007 //元素总个数
int sum[maxn<<2];//sum求和 开四倍空间
int a[maxn],n;//存原数组下标[1,n]
int add[maxn<<2];//懒惰标记
/*建树*/
//pushup 函数更新节点信息,这里是求和。
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//build 函数建树
void build(int l,int r,int rt)
{//[l,r] 表示当前节点区间, rt 是当前节点实际存储位置
    if(l==r) {//若到达叶节点
        sum[rt]=a[l];//存储a数组的值
        return ;
    }
    int mid=(l+r)>>1;
    //左右递归
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    //更新信息
    pushup(rt);
}
//点修改
void update_dot(int L,int C,int l,int r,int rt)
{//[l,r]表示当前区间 rt是当前节点编号
    if(l==r)
    {
        sum[rt]+=C;
        return ;
    }
    int mid=(l+r)>>1;
    //根据条件判断往左子树调用还是往右
    if(L<=mid) update_dot(L,C,l,mid,rt<<1);
    else update_dot(L,C,mid+1,r,rt<<1|1);
    pushup(rt);//子节点的信息更新了,所以本节点也要更新
}
//区间修改
void update_qu(int L,int R,int C,int l,int r,int rt)
{//L,R表示操作区间 l,r 表示当前节点区间,rt表示当前节点编号
    if(l>=L&&R>=r)//如果本区间完全在操作区间[L,R] 之内
    {
        sum[rt]+=C*(r-l+1);//更新数字和,向上保持正确
        add[rt]+=C;//增加add标记 表示 本区间的sum正确,子区间的sum仍需要根据add的值来调整
        return ;
    }
    int mid=(l+r)>>1;
    pushdown(rt,mid-l+1,r-mid);//下推标记
    //这里判断左右子树跟[L,R]有无交集,有交集才递归
    if(L<=mid) update_qu(L,R,C,l,mid,rt<<1);
    if(R>mid) update_qu(L,R,C,mid+1,r,rt<<1|1);
    pushup(rt);//更新本节点信息
}
// 下推标记
void pushdown(int rt,int ln,int rn)
{//ln rn 为 左子树 右子树的数字数量
    if(add(rt))
    {
        //下推标记
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        //修改子节点的sum使之与对应的add相对应
        sum[rt<<1]+=add[rt]*ln;
        sum[rt<<1|1]+=add[rt]*rn;
        //清除本节点的标记
        add[rt]=0;
    }
}
//区间查询 (求[L,R]和)
int Query(int L,int R,int l,int r,int rt)
{//[L,R]表示操作区间 [l,r]表示当前区间 rt表示当前节点编号
    if(l>=L&&R>=r)
    {//在区间内直接返回
        return sum[rt];
    }
    int mid=(l+r)>>1;
    //左[l,mid] 右[mid+1,r] 求和区间[L,R];
    //累加答案
    int ans=0;
    if(L<=mid) ans+=Query(L,R,l,mid,rt<<1);//左子区间与[L,R]有重叠,递归
    if(R>mid) ans+=Query(L,R,mid+1,r,rt<<1|1);//右子区间与[L,R]有重叠,递归
    return ans;
}
/*懒惰标记
含义:本节点的统计信息已经根据标记更新过了,但是本节点的节点仍需要
进行更新
*/
//建树
build(1,n,1);
//点修改
update_dot(L,C,1,n,1);
//区间修改
update_qu(L,R,C,1,n,1);
//区间查询
int ANS=Query(L,R,1,n,1);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值