线段树模板

这篇博客详细介绍了线段树的实现,包括单点查询、单点修改、区间询问和区间修改等功能。提供了完整的代码实现,包括不同操作的递归处理和关键的标记下传、插入和删除操作。

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

所有的线段树各个部分的代码

//【单点查询】查询一个点的状态,设待查询点为x 
void Ask(int k) //k表示结构体数组的编号
{
    if(tree[k].l==tree[k].r) //当前结点的左右端点相等,是叶子节点,最终答案
    { 
        ans=tree[k].w;
        return ;
    }
    int mid=(tree[k].l+tree[k].r)/2;
    if(x<=mid) 
    {
        Ask(k*2); //目标位置比中点靠左,就递归左孩子else Ask(k*2+1); //反之,递归右孩子
    }

 //【单点修改】更改某一个点的状态。如:第x个数增加d
void Add(int k,int x,int d) //添加到点
{
    if(x<Tree[k].a||x>Tree[k].b)
    {
        return;//不相交
    }
    if(Tree[k].a==Tree[k].b)
    {    
        Tree[k].minn+=d;
        return ;
    }//边界叶结点Add(2*k,x,d); //递归左子树
    Add(2*k+1,x,d); //递归右子树
    Tree[k].minn=min(Tree[2*k].minn,Tree[2*k+1].minn);
}

//【区间询问】询问到区间
void Ask(int k,int L,int R) //询问到区间
{
    if(R<Tree[k].a||L>Tree[k].b)
    {
        return; //不相交
    }
    if(L<=Tree[k].a&&R>=Tree[k].b)
    {
        minn=min(minn,Tree[k].min);
        return;
    }
    Ask(2*k,L,R); //递归左子树
    Ask(2*k+1,L,R); //递归右子树
}

 //【区间修改】针对单点查询,不带懒标记
void Add(int v,int L,int R,int d)
{
    if(L>tree[v].b||R<tree[v].a)
    {
        return; //不相交
    }
    if(L<=tree[v].a&&R>=tree[v].b)
    {
        tree[v].add+=d;
        return;
    }
    Add(2*v,L,R,d); //递归左子树
    Add(2*v+1,L,R,d); //递归右子树
}

//【单点查询】针对不带懒标记的区间修改
void Ask(int v,int x)
{
    if(x>tree[v].b||x<tree[v].a)
    {
        return;
    }
    if(x>=tree[v].a&&x<=tree[v].b)
    {
        Ans+=tree[v].add;
    }
    if(tree[v].a==tree[v].b)
    {
        return; //边界叶结点Ask(2*v,x);
    }
    Ask(2*v+1,x);

//【懒标记的关键操作1】懒标记的下传
void Pushdown(int v) //标记下传
{   
    if(Tree[v].bj==-1) //已擦去,标记下传
    { 
        Tree[v*2].bj=Tree[v*2+1].bj=-1;
        Tree[v*2].s=Tree[v*2+1].s=0;
        Tree[v].bj=0; //重要语句
    }
    if(Tree[v].bj==1) //已涂色,标记下传
    {
        Tree[v*2].bj=Tree[v*2+1].bj=1;
        Tree[v*2].s=Tree[v*2].b-Tree[v*2].a+1;
        Tree[v*2+1].s=Tree[v*2+1].b-Tree[v*2+1].a+1;
        Tree[v].bj=0; //标记下传之后清空当前节点标记
    }

//【插入操作】区间涂上颜色
void Pushup (int v)
{
    Tree[v].s=Tree[v*2].s+Tree[v*2+1].s;
} //更新附加信息
void Insert(int v,int L,int R) //线段树的插入
{
    if(Tree[v].b<L||Tree[v].a>R)
    {
        return; //若涂色的区域与该线段不相交,则退出
    }
    if(Tree[v].bj==1) 
    {
        return;//若该线段被标记涂色,则退出//若涂色的区域覆盖了该线段,则该线段的状态变为被涂色,并退出
    }
    if(L<=Tree[v].a&&Tree[v].b<=R) //完全覆盖情况
    {
        Tree[v].bj=1;Tree[v].s=Tree[v].b-Tree[v].a+1;
        return;
    }
    Pushdown(v); //标记下传
    Insert(v*2,L,R); //插入左右子树
    Insert(v*2+1,L,R);
    Pushup (v); //重新计算本结点的附加信息

//【删除操作】区间擦去颜色
void Delete(int v,int L,int R) //线段树的删除
{
    if(Tree[v].b<L||Tree[v].a>R)
    {
        return; //若删除的区域与该线段不相交,则退出
    }
    if(Tree[v].bj==-1)
    {
        return; //若该线段被标记删除,则退出
    }
    //若删除的区域覆盖了该线段,则该线段的状态变为未被涂色,并退出
    if(L<=Tree[v].a&&Tree[v].b<=R)
    {
        Tree[v].bj=-1;Tree[v].s=0;
        return;
    }
    Pushdown(v); //标记下传
    Delete(v*2,L,R); //删除左右子树
    Delete(v*2+1,L,R);
    Pushup (v); //重新计算本结点的附加信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值