【算法学习】线段树基础版

一 线段树

1.概念

线段树可以理解为一个二叉树,如果是利用线段树求区间的和,那么每个结点的权值维护的是结点所维护区间的和,再将该区间一分为二,分别交由左右儿子维护。

拿区间1 - 4的和来举例子,

根结点维护的是区间1 到 4,结点权值是该区间的和,再将区间一份为二,其左儿子维护的是 1 - 2,右儿子维护的是 3 - 4 ,以此类推,直到结点维护的区间长度为1。

不难看出,每个节点的权值等于左右儿子的权值之和。

2.基本步骤

1.构造线段树

清楚了线段树的概念后,很容易构造线段树,一般算法题都是通过数组模拟二叉树,本文也采用这种方式。

struct Tree {int l, r, weight;
} tree[N];
using namespace std;void build_tree(int i, int l, int r) {if (l == r) {tree[i] = {l, r, w[l]};return;}int mid = l + r >> 1;//构建左子树build_tree(i<<1, l, mid);//构建右子树build_tree(i<<1|1, mid + 1, r);//节点权值int sum = tree[i * 2].weight + tree[i * 2 + 1].weight;//更新区间tree[i] = {l,r,sum};}
2.区间查询

从根节点开始找目标区间

1.结点维护的区间是目标区间的子集,直接返回结点权值

2.左子树与目标区间有交集,递归左子树

2.右子树与目标区间有交集,递归右子树

4.返回sum

拿查找2-3区间和举例

从根节点开始,目标区间和左子树有交集,递归左子树,目标区间和右子树有交集 ,递归右子树;

接着看根节点左儿子,目标区间只和右子树有交集,递归右子树,

看根节点右儿子,目标区间只和左子树有交集,递归左子树, 

再向下递归发现,节点维护区间刚好是目标区间的子集,直接返回权值,结束向下递归。

代码

int query(int i,int l,int r){//结点维护区间是目标区间的子集,直接返回权值if(tree[i].l>=l&&tree[i].r<=r)return tree[i].weight;int mid = tree[i].l + tree[i].r >>1;int sum = 0;if(l<=mid) sum += query(i*2,l,r);if(r>mid)sum+= query(i*2+1,l,r);return sum;
}

3.区间修改 

从根节点开始找目标区间

1.结点维护的区间是目标区间的子集,修改权值,返回

2.左子树与目标区间有交集,递归左子树

2.右子树与目标区间有交集,递归右子树

4.更新结点权值(pushup)

拿给2-3区间加1和举例

从根节点开始,目标区间和左子树有交集,递归左子树,目标区间和右子树有交集 ,递归右子树;

接着看根节点左儿子,目标区间只和右子树有交集,递归右子树,

看根节点右儿子,目标区间只和左子树有交集,递归左子树, 

再向下递归发现,节点维护区间刚好是目标区间的子集,直接修改权值,结束向下递归。

代码

void pushup(int i){tree[i].weight = tree[i<<1].weight + tree[i<<1|1].weight;
}
void modify(int i, int l, int r,int v)
{if(tree[i].l>=l&&tree[i].r<=r) tree[i].weight+=v*(tree[i].r - tree[i].l+1);else{int mid = tree[i].l + tree[i].r >>1;if(l<=mid) modify(i<<1,l,r,v);if(r>mid) modify(i<<1|1,l,r,v);pushup(i);}}

例题

1.动态求连续区间和

给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列[a,b]的连续和。

输入格式

第一行包含两个整数 n 和 m,分别表示数的个数和操作次数。

第二行包含n个整数,表示完整数列。

接下来 m 行,每行包含三个整数k, a, b(k = 0,表示求子数列[a, b]的和;k = 1,表示第 a 个数加b)。

数列从1开始计数。

输出格式

输出若干行数字,表示k=0 时,对应的子数列[a, b]的连续和。

数据范围

1≤n≤100000,

1≤m≤100000,

1≤a≤b≤n,

数据保证在任何时候,数列中所有元素之和均在 int 范围内。

输入样例:

10 5
1 2 3 4 5 6 7 8 9 10
1 1 5
0 1 3
0 4 8
1 7 5
0 4 8
1
2
3
4
5
6
7
输出样例:

11
30
35
1
2
3

ans

#include <cstdio>
#include <iostream>
#include <algorithm>const int N = 1e5 + 10;
struct segment_tree {int l, r, weight;
} tree[N*4];
int n,m;
int w[N];
using namespace std;void build_tree(int i, int l, int r) {if (l == r) {tree[i] = {l, r, w[l]};return;}int mid = l + r >> 1;//构建左子树build_tree(i<<1, l, mid);//构建右子树build_tree(i<<1|1, mid + 1, r);//节点权值int sum = tree[i * 2].weight + tree[i * 2 + 1].weight;//更新区间tree[i] = {l,r,sum};}
void pushup(int i){tree[i].weight = tree[i<<1].weight + tree[i<<1|1].weight;
}
int query(int i,int l,int r){//结点维护区间是目标区间的子集,直接返回权值if(tree[i].l>=l&&tree[i].r<=r)return tree[i].weight;int mid = tree[i].l + tree[i].r >>1;int sum = 0;if(l<=mid) sum += query(i<<1,l,r);if(r>mid)sum+= query(i<<1|1,l,r);return sum;
}void modify(int i, int l, int r,int v)
{if(tree[i].l>=l&&tree[i].r<=r) tree[i].weight+=v*(tree[i].r - tree[i].l+1);else{int mid = tree[i].l + tree[i].r >>1;if(l<=mid) modify(i<<1,l,r,v);if(r>mid) modify(i<<1|1,l,r,v);pushup(i);}}
int main()
{scanf("%d%d", &n, &m);for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);build_tree(1, 1, n);int k, a, b;while (m -- ){scanf("%d%d%d", &k, &a, &b);if (k == 0) printf("%d\n", query(1, a, b));else modify(1, a,a, b);}return 0;
}

感谢你的阅读,希望本文对你有所帮助。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/641678.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 The Sandbox 与小战象一起庆祝泰国新年!

加入探险行列&#xff0c;与小战象一起庆祝 2024 年泰国新年&#xff01;在热闹非凡的泼水节上寻找宋干小姐。 即刻起至 6 月 13 日参与游戏&#xff0c;有机会赢取独家 NFT&#xff01; 按此进入游戏体验&#xff1a; https://www.sandbox.game/en/experiences/Khan%20Kluay%…

以赛促学、生态共建 | 软通动力子公司鸿湖万联成功举办基于x86架构的OpenHarmony应用生态挑战赛

近日&#xff0c;由开放原子开源基金会、央视网、江苏省工业和信息化厅、无锡市人民政府、江苏软件产业人才发展基金会、苏州工业园区、无锡高新区等共同承办&#xff0c;鸿湖万联参与共建的“基于x86架构的OpenHarmony应用生态挑战赛”决赛路演在无锡圆满落幕。本次挑战赛历时…

Centos7.9安装rabbitmq

1. 概述 AMQP&#xff0c;即 Advanced Message Queuing Protocol&#xff08;高级消息队列协议&#xff09;&#xff0c;是一个网络协议&#xff0c;是应用层协议的一个开放标准&#xff0c;为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息&#xff0c;并不…

如何在PostgreSQL中使用索引覆盖扫描提高查询性能?

文章目录 解决方案1. 创建合适的索引2. 确保查询能够使用索引覆盖扫描3. 调整查询以利用索引覆盖扫描4. 监控和调优 示例代码1. 创建索引2. 编写查询3. 检查是否使用索引覆盖扫描4. 调整索引 总结 在PostgreSQL中&#xff0c;索引是提高查询性能的关键工具之一。索引允许数据库…

vscode自动生成项目目录结构

目录结构如下&#xff1a; 生成步骤如下&#xff1a; vscode安装插件&#xff0c;project-tree安装之后按ctrlshiftp&#xff0c;并输入Project Tree回车点击要生成目录的项目&#xff0c;回车将项目目录生成并存储到README.md中

Redis篇:实现短信登录

实现的是黑马点评的手机号短信验证码登录功能 1.实现流程 发送验证码&#xff1a; 用户在提交手机号后&#xff0c;会使用正则表达式校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&a…

【力扣 Hot100 | 第六天】4.21(最长连续序列)

文章目录 10.最长连续序列10.1题目10.2解法&#xff1a;哈希法10.2.1哈希思路10.2.2代码实现 10.最长连续序列 10.1题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时…

HSB矩形调色板设计和计算方法

HSB矩形调色板设计和计算方法 RGB调色板绘制较容易&#xff0c;HSB调色板较难绘制&#xff0c;前些天发文介绍了几个矩形样例的绘制方法&#xff0c;今介绍矩形的HSB调色板的设计方法和H,S,B值的计算方法&#xff0c;好东西必须与大家分享。 此文介绍HSB调色板和选色条的绘制方…

idea上传项目到gitee(码云)

1、打开码云&#xff0c;新建仓库 2、创建 3、这就是创建成功的页面 4、复制仓库地址&#xff0c;后面需要用到 2、打开我们的项目&#xff1a;例如我现在的项目 1、idea创建git仓库 2、选择我们项目文件夹的目录 3、查看文件是否变色&#xff0c;变色表示成功了 4、添加到缓…

【Java】Java基础 使用集合实现斗地主分牌

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 今天使用集合TreeSet来实现一个斗地主的分牌流程。 TreeSet集合的一个特点就是 元素有序&#xff0c;这样就方便我们分的牌自动排序。 0.思路 1.创建玩家手牌集合 我们到时候分的牌都存储在这里&#xff0c;但你可能会…

Web前端安全问题分类综合以及XSS、CSRF、SQL注入、DoS/DDoS攻击、会话劫持、点击劫持等详解,增强生产安全意识

前端安全问题是指发生在浏览器、单页面应用、Web页面等前端环境中的各类安全隐患。Web前端作为与用户直接交互的界面&#xff0c;其安全性问题直接关系到用户体验和数据安全。近年来&#xff0c;随着前端技术的快速发展&#xff0c;Web前端安全问题也日益凸显。因此&#xff0c…

山海鲸电力看板:运维数据一目了然

在信息化高速发展的今天&#xff0c;电力行业的运维管理也迎来了前所未有的变革。山海鲸可视化智慧电力运维可视化看板&#xff0c;以其独特的数据整合能力和直观的可视化效果&#xff0c;成为了电力行业运维管理的得力助手&#xff0c;为电力的稳定运行提供了强大的技术支撑。…