线段树算法模版

本文详细介绍了线段树算法的基本思路,包括pushup、build、query和modify四个核心函数,以及如何通过示例和代码实现对区间数据的操作,适合初学者理解线段树数据结构的应用。
摘要由CSDN通过智能技术生成

算法思路

该算法,主要有四种基本函数
1.pushup(u):用子节点信息来更新当前节点信息(把信息往上传递)

2、build(u,l,r):在一段区间上初始化线段树,其中u表示根结点,l表示左边界,r表示右边界

3、query(u,l,r):查询某段区间的和,其中u表示根结点,l表示左边界,r表示右边界

4、modify(u,x,v):修改操作,在u结点中,x位置加上v

线段数图解

在这里插入图片描述

修改操作

在这里插入图片描述

查询操作

在这里插入图片描述

模版题

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 1e5 + 10;
int w[N];

struct Node
{
    int l, r;
    int sum;
}tr[N * 4];
//这里一般是数据的4倍

void pushup(int u)
{
    //  u << 1 | 1 --> 2x + 1
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void  build(int u, int l, int r)
{
    //分到不能再分了,就剩一个数了,结束递归
    if(l == r)  tr[u] = {l ,r , w[r]};
    else
    {
        //一定要注意进行初始化
        tr[u] = {l, r};
        
          //向下取整分区间, [l, mid] [mid + 1, r],分区间
        int mid = (l + r) >> 1;
        build(u << 1, l , mid), build(u << 1 | 1, mid + 1 , r);
        
        //区间分了,节点信息要更新
        pushup(u);
    }
}

int query(int u, int l, int r)
{
    //序列完全包含要求的区间
    if(tr[u].l >= l && tr[u].r <= r)    return tr[u].sum;
    
    int mid = (tr[u].l + tr[u].r) >> 1;
     int sum = 0;
    
    //区间 [l, mid] [mid + 1, r] 
    //注意:此处代码写法  并且query区间始终是l和r
    //并且此处不能写else if
    
    if(l <= mid) sum = query(u << 1, l, r); //与左区间右交集
    if(r > mid)    sum += query(u << 1 | 1, l, r);
    
    return sum;
}


//修改某个数 (sum加上某个数)
void modify(int u, int x ,int v)
{
    //就剩一个数,这个数组的sum加上v
    if(tr[u].l == tr[u].r)  tr[u].sum += v;
    else
    {
        int mid = (tr[u].l + tr[u].r) >> 1;
        
        //二叉树
        //这个数小于mid,递归左子树
        if(x <= mid)    modify(u << 1, x, v);
        else if(x > mid)    modify(u << 1 | 1, x, v);
        
        //数改变,更新节点信息
        pushup(u);
    }
    
}

int n, m;

int main()
{
    scanf("%d %d", &n, &m);
    
    for(int i = 1; i <= n; i++)   scanf("%d", &w[i]);
    
    //初始化线段树, 根节点1开始,节点从1到n
    build(1, 1, n);
    
    while(m--)
    {
        int k, a, b;
        scanf("%d %d %d", &k, &a, &b);
        
        if(k == 0)  printf("%d\n", query(1, a, b));
        else if(k = 1)  modify(1, a, b);
    }
    
    return 0;
    
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔了岁月.c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值