简单线段树

2021年7月30

线段树是干什么的?

更新,维护,查询某区间的某项值,如区间和等。

线段树的原理

与树状数组类似,线段树通过直接建树来保存区间的结点,如图:

如何建图?

下面以求序列区间和为例:

当存放一个数字时,它需要将每个子区间的值返回到父节点之上,依次返回直到最大的区间上。此时,一个区间接收到的值就是它所有子区间值的和。

由于每个区间的大小都为1<<i,0<=i<=n,因此,我们构建的树是一颗二叉树。按行进行标号,易得第i个区间的两个子区间标号分别为i * 2与i * 2 + 1。

依据这个性质,易想到使用递归方式进行存图。代码如下:

int built(int i, int l, int r){tre[i].l=l;tre[i].r=r;//更新第i个区间的左右边界if(l==r) return tre[i].sum=a[i];//若区间大小为1,则更新值后直接返回int mid=(l+r/2);return tre[i].all+=built(i*2,l,mid)+built(i*2+1,mid+1,r);//其区间和等于左右子树的区间和,更新后返回
}
单点更新

对于每次查找,只需要找到其位置,更新即可

void onemodify(int i,int pos,int k){if (tre[i].r<l || tre[i].l>r)return;if (tre[i].l >= l && tre[i].r <= r) {tre[i].all += k;}modify(i * 2, l, r, k);modify(i * 2 + 1, l, r, k);
}
如何对整个区间进行修改?

给出区间l与r,要求区间内每个点加k。从树上进行遍历,对每个在区间l-r内的点进行更新值。

void modify(int i, int l, int r, int k) {if (tre[i].r<l || tre[i].l>r)return;//不在区间内,直接返回if (tre[i].l <= l && tre[i].r >= r) {tre[i].all += k*(min(r-l,tre[i].r - tre[i].l) +1);//更改区间在目前结点内,更新最大可更新值}modify(i * 2, l, r, k);modify(i * 2 + 1, l, r, k);
}

但是,这种更新方式,其复杂度是O(nlog(n)),再加上m次更新,其复杂度达到了O(nmlog(n)),比直接枚举还要多了log级别的时间复杂度。

如何将其优化到O(log(n))的复杂度?

增加一个标记:懒惰标记

此标记意味着对于此区间内所有子区间的结点,都有增加了k。

void modify(int i, int l, int r, int k){if (tre[i].r<l || tre[i].l>r)return;tre[i].all += k * (min(r, tre[i].r) - max(l, tre[i].l) + 1);//两区间交集就是需要更新值的部分if ((tre[i].l >= l && tre[i].r <= r)) {tre[i].lazy += k;return;}modify(i * 2, l, r, k);modify(i * 2 + 1, l, r, k);
}

此时,就不用查找到每一个长度为1的区间了。

注:此时需在建图时将tre中的lazy初始化为0.

模板样例

第一行输入三个数n,m,q,分别为数组大小,修改次数及查询次数,随后一行有n个数字,分别是a1…n,第3行到第2+m行,每行三个数,分别为区间边界及每个数修改的值,接下来q行,每行两个数,分别为要查询区间的左右边界。

每次查询,输出一行数字,代表区间和。

输入样例:

8 4 7
1 5 2 3 6 9 7 2
2 3 2
3 5 7
3 3 1
4 6 8
1 8
3 3
3 3
2 5
4 8
6 8
5 7

输出样例:

85
12
12
58
65
26
45
代码
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<string.h>using namespace std;struct Tree {int l, r;int all;int lazy;
}tre[1005];int n, m, q;
int  sic[1005], ans;
string row;int builtre(int i, int l, int r) {tre[i].l = l; tre[i].r = r; tre[i].lazy = 0;if (l == r)return tre[i].all=sic[l];int mid = (l + r) / 2;tre[i].all += builtre(i * 2, l, mid);tre[i].all += builtre(i * 2 + 1, mid + 1, r);return tre[i].all;
}void modify(int i, int l, int r, int k) {if (tre[i].r<l || tre[i].l>r)return;tre[i].all += k * (min(r, tre[i].r) - max(l, tre[i].l) + 1);if ((tre[i].l >= l && tre[i].r <= r)) {tre[i].lazy += k;return;}modify(i * 2, l, r, k);modify(i * 2 + 1, l, r, k);
}int solve(int i, int l, int r,int lazy) {if (tre[i].l >= l && tre[i].r <= r) {ans += tre[i].all;ans += (tre[i].r - tre[i].l + 1) * lazy;return ans;}if (tre[i].l > r || tre[i].r < l)return 0;if (tre[i].r >= l) solve(i * 2, l, r,lazy + tre[i].lazy);if (tre[i].l <= r) solve(i * 2 + 1, l, r, lazy + tre[i].lazy);return ans;
}int main() {cin >> n >> m >> q;for (int i = 0; i < n; i++){cin >> sic[i + 1];}builtre(1, 1, n);int a, b, k;while (m--) {cin >> a >> b >> k;modify(1, a, b, k);}while (q--) {cin >> a >> b;ans = 0;cout << solve(1, a, b, tre[1].lazy) << endl;}return 0;
}

后练习代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<string.h>
typedef long long ll;using namespace std;int n, m;
int sic[100005];struct P {int l, r;int key, lazy;
}tre[100005];int built(int p, int l, int r) {tre[p].l = l; tre[p].r = r;if (l == r)return tre[p].key = sic[l];int mid = (l + r >> 1);return tre[p].key = built(p * 2, l, mid) + built(p * 2 + 1, mid + 1, r);
}void insert(int p, int l, int r, int key) {if (tre[p].r<l || tre[p].l>r)return;if (tre[p].l >= l && tre[p].r <= r) {tre[p].lazy += (tre[p].r-tre[p].l+1)*key; return;}tre[p].lazy += (1+min(r - l, min(tre[p].r - l, r - tre[p].l))) * key;insert(2 * p, l, r, key); insert(2 * p + 1, l, r, key);
}int findkey(int p, int l, int r) {if (tre[p].r<l || tre[p].l>r)return 0;if (tre[p].l >= l && tre[p].r <= r) return tre[p].key + tre[p].lazy;return findkey(2 * p, l, r) + findkey(2 * p + 1, l, r);
}int main() {cin >> n;for (int i = 1; i <= n; i++){cin >> sic[i];}built(1, 1, n);while (1) {int a, l, r, k;cin >> a;if (!a)break;cin >> l >> r;if (a == 2) {cin >> k;insert(1, l, r, k);}elsecout << findkey(1, l, r) << endl;}return 0;
}

线段树-简单线段树模板相关推荐

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  2. python:线段树区间修改 + 区间查询 模板 + 坑点总结

    from functools import reduceclass SegTree:'''支持增量更新,覆盖更新,序列更新,任意RMQ操作基于二叉树实现初始化:O(1)增量更新或覆盖更新的单次操作复杂 ...

  3. 模板:二维线段树(线段树套线段树)

    文章目录 问题 解析 单点修改 询问 完整代码 标记永久化 代码 所谓二维线段树,就是有两个维度的线段树 (逃) 问题 给出一个矩形 要求支持以下操作: 1.询问一个子矩形的最值 2.修改某一个单点的 ...

  4. java 区间树_线段树(区间树)之区间染色和4n推导过程

    前言 线段树(区间树)是什么呢?有了二叉树.二分搜索树,线段树又是干什么的呢?最经典的线段树问题:区间染色:正如它的名字而言,主要解决区间的问题 一.线段树说明 1.什么是线段树? 线段树首先是二叉树 ...

  5. 【牛客 - 157C】PH试纸(前缀和,或权值线段树,主席树)

    题干: 链接:https://ac.nowcoder.com/acm/contest/157/C 来源:牛客网 题目描述 PH试纸,是一种检测酸碱度的试纸,试纸红色为酸性,蓝色为碱性. HtBest有 ...

  6. 吊打线段树的超级树状数组

    你是否讨厌线段树那冗长的代码?你是否还在因为线段树的难调试而满头♂dark汗?那么,请不要错过!超级树状数组特价!只要998,只要998! ##¥--#--¥%--&%¥--ER#%$#$#^ ...

  7. 【bzoj1146】 [CTSC2008]网络管理Network【树链剖分+树套树+二分 线段树套Treap】

    1146: [CTSC2008]网络管理Network Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公 ...

  8. Codeforces Round #439 (Div. 2) E. The Untended Antiquity 二维线段树||二维树状数组

    http://codeforces.com/contest/869/problem/E 题意:n*m的矩阵,q次操作,三种类型 类型1:给指定矩阵加上围栏 类型2:给指定矩阵去掉围栏 类型3:查询两点 ...

  9. 【线段树】线段树及其相关 复习

    划分树: poj2104 K-th number /*******************************\* @prob: poj2104 K-th number ** @auth: Wan ...

最新文章

  1. gradle idea java ssm_应用框架:IDEA+Gradle创建MyBatis+SpringMVC项目
  2. 用pip安装tensorflow报错SyntaxError: invalid syntax
  3. 数据库设计的第三范式
  4. MyEclipse中导入Spring 4.0源码
  5. 头上有多少根头发算秃头?
  6. 在计算机领域客观事物的属性表示为数据,数据与信息试题解析
  7. python字符串二(find();index();count();rfind();rindex();replace();替换;.split();分割;join();合并)
  8. 300 秒搞定第一超算 1 万年的计算量,量子霸权时代已来? | CSDN 博文精选
  9. Python——内置类型
  10. 13. ZooKeeper最佳实践
  11. p8b75-m修改bios文件_傻瓜式方法:VMWARE使用NAT方式彻底解决开发板无法挂载ubuntu文件的难题...
  12. 开氏温度与摄氏度换算_温度是怎么来的,有没有物质没有温度?
  13. 如何将word公式粘贴到动易CMS里面
  14. 2023年全国最新二级建造师精选真题及答案49
  15. 基于FPGA低频方波测量-频率与占空比
  16. 中粮集团智慧园区网,锐捷用匠心打造工业4.0时代智能工厂
  17. ORACLE ERP 系统架构与应用实践
  18. python中英文古风排版_2017年天梯赛部分真题加Pat部分题目(1)
  19. 【SCCB接口协议简介(适用于OV系列摄像头)】
  20. python把pdf转word_手把手|20行Python代码教你批量将PDF文件转为Word格式(包教包会)...

热门文章

  1. python观察日志(part19)--关于iPython中的In[]和Out[]
  2. Psych101(part3)--Day3
  3. 网络编程(part2)--文件读写之打开/读取/写入
  4. 网卡重启影响nfs吗_NFS网络储存系统
  5. onmounted vue3_基于项目时间阐述vue3.0新型状态管理和逻辑复用方式
  6. LeetCode53:最大子序和(分治思想,Python3实现)
  7. HTML 按钮(button)的 disable 属性和 disable property
  8. SAP Commerce Cloud 项目 Spartacus 入门
  9. 介绍一个 Windows 10 资源管理器的替代工具 - Explorer++
  10. 什么是 SAP vocabulary-based annotations