线段树(nb)
今天刚学习了线段树,赶紧趁热打了两遍模版
下面都是线段树的基本操作,这个板子是维护的区间中的最大值,当然修改change和build包括线段树中的data可以维护区间上的不同信息。
首先介绍一下线段树这种数据结构吧
线段树是一种基于分治思想的二叉树结构,用于在区间上进行信息的统计与维护
板子的一些默认信息
1、线段树的每个结点都代表一个区间。
2、线段树具有唯一的跟结点,代表的区间是整个统计范围,即[1~N]。
3、线段树的每个叶子结点都代表一个长度为1的元区间[x, x]。
4、 对于每个内部节点[l, r],它的左子结点是[l, mid], 右子结点是[mid + 1, r]
#include <iostream>
using namespace std;
//线段树是基于分治的思想实现的
//struct数组存储线段树
struct SegmentTree
{
int l, r;
int data;
}t[100 * 4];
int a[100];
//用线段树维护每个区间的最大值
void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r;
if(r == l) {t[p].data = a[l]; return ;}
int mid = (l + r) >> 1;
build(p*2, l, mid);
build(p*2 + 1, mid + 1, r);
t[p].data = max(t[p * 2].data, t[p*2 + 1].data);
}
//调用入口
// build(1, 1, n);
//线段树的单点修改
void change(int p, int x, int v)
{
if(t[p].l == t[p].r) {t[p].data = v; return ;}//找到要修改的叶子结点
int mid = (t[p].l + t[p].r) >> 1;
if(x <= mid) change(p * 2, x ,v); //x属于左半区间
else change(p * 2 + 1, x, v); // 行属于右半区间
t[p].data = max(t[p * 2].data, t[p * 2 + 1].data);//从下往上更新信息
}
//线段树的区间查询
int ask(int p, int l, int r)
{
if(l <= t[p].l && r >= t[p].r) return t[p].data;
int mid = (t[p]. l + t[p].r) >> 1;
int val = -(1 << 30); //初始化为负无穷大
if(l <= mid) val = max(val, ask(p * 2, l, r));
if(r > mid) val = max(val, ask(p * 2 + 1, l ,r));
return val;
}
//调用出口 cout << ask(1, 1, r) << endl;
int main()
{
int n;cin >> n;
for(int i = 1; i <= n; ++ i) cin >> a[i];
build(1, 1, n);
cout << ask(1, 2, 3);
}
若要维护区间最大连续子段和
#include <iostream>
using namespace std;
//线段树是基于分治的思想实现的
//struct数组存储线段树
struct SegmentTree
{
int l, r;
int lmax, rmax, sum, data;
}t[100 * 4];
int a[100];
//用线段树维护每个区间的信息
void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r;
if(r == l)
{
t[p].sum = a[l];
t[p].lmax = a[l];
t[p].rmax = a[l];
t[p].data = a[l];
return ;
}
int mid = (l + r) >> 1;
build(p*2, l, mid);
build(p*2 + 1, mid + 1, r);
t[p].lmax = max(t[p * 2].lmax, t[p * 2].sum + t[p * 2 + 1].lmax);
t[p].rmax = max(t[p * 2 + 1].rmax, t[p * 2 + 1].sum + t[p * 2].rmax);
t[p].data = max(t[p * 2].data, t[p * 2 + 1].data);
t[p].data = max(t[p].data, t[p * 2].rmax + t[p * 2 + 1].lmax);
}
//调用入口
// build(1, 1, n);
//线段树的单点修改
void change(int p, int x, int v)
{
if(t[p].l == t[p].r) {t[p].data = v; return ;}//找到要修改的叶子结点
int mid = (t[p].l + t[p].r) >> 1;
if(x <= mid) change(p * 2, x ,v); //x属于左半区间
else change(p * 2 + 1, x, v); // 行属于右半区间
//从下往上更新信息
t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
t[p].lmax = max(t[p * 2].lmax, t[p * 2].sum + t[p * 2 + 1].lmax);
t[p].rmax = max(t[p * 2 + 1].rmax, t[p * 2 + 1].sum + t[p * 2].rmax);
t[p].data = max(t[p * 2].data, t[p * 2 + 1].data);
t[p].data = max(t[p].data, t[p * 2].rmax + t[p * 2 + 1].lmax);
}
//线段树的区间查询
int ask(int p, int l, int r)
{
if(l <= t[p].l && r >= t[p].r) return t[p].data;
int mid = (t[p]. l + t[p].r) >> 1;
int val = -(1 << 30); //初始化为负无穷大
if(l <= mid) val = max(val, ask(p * 2, l, r));
if(r > mid) val = max(val, ask(p * 2 + 1, l ,r));
return val;
}
//调用出口 cout << ask(1, 1, r) << endl;
int main()
{
int n;cin >> n;
for(int i = 1; i <= n; ++ i) cin >> a[i];
build(1, 1, n);
cout << ask(1, 1, 5);
}
可以看出我们只需要修改build和change部分即可,只需要加入我们想要维护区间的额外信息。
线段树也太好用了吧QWQ!!!
线段树(nb)的更多相关文章
- HDU4614【线段树。】
果然看了理解了一下大牛的代码然后自己敲结果果然有不少错误 回复说,线段树做为一种数据结构,最好以一种风格过一题裸的然后作为自己的模板.. 二分写的也很恶心哪 还有题目稍复杂一点的注定得推敲各种公式,不 ...
- HDU1394 Minimum Inversion Number(线段树OR归并排序)
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】
题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...
- BZOJ-2298|区间dp|线段树
problem a Description 一次考试共有n个人参加,第i个人说:"有ai个人分数比我高,bi个人分数比我低."问最少有几个人没有说真话(可能有相同的分数) Inpu ...
- Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)
先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...
- loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增
题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...
- hdu-1394(线段树&逆序数的性质和求法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题目大意: 给出一个序列,一对逆序数就是满足i<j&&a[i]>a[ ...
- 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 657 Solved: 274[Su ...
- 字符串(tjoi2016,heoi2016,bzoj4556)(sam(后缀自动机)+线段树合并+倍增+二分答案)
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为\(n\)的字符串\(s\),和\(m\)个问题.佳媛姐姐必须正确回答这\(m\)个问题, ...
- 【题解】洛谷P1198 [JSOI2008] 最大数(线段树)
洛谷P1198:https://www.luogu.org/problemnew/show/P1198 思路 一道水水的线段树 20分钟A掉 这道题只涉及到单点修改和区间查询 所以这道题甚至不用Laz ...
随机推荐
- 详解RISC v中断
声明 本文为本人原创,未经许可严禁转载.部分图源自网络,如有侵权,联系删除. RISC-V 中断与异常 trap(陷阱)可以分为异常与中断.在 RISC v 下,中断有三种来源:software in ...
- ObjectInputStream_报错问题
报错: Exception in thread "main" java.io.StreamCorruptedException: invalid stream header: CE ...
- 【Spring】@RequestBody的实现原理
@RequestBody注解可以用于POST请求接收请求体中的参数,使用方式如下: @Controller public class IndexController { @PostMapping(va ...
- RAT蓝队自动化测试框架
RAT蓝队自动化测试框架 介绍 RAT 是根据 MITRE ATT&CK 战术矩阵测试蓝队检测能力的脚本框架,由 python2.7 编写,共有 50 多种不同 ATT&CK 技术点和 ...
- 图像阈值_有cv2.threshold,cv2.adaptiveThreshold 等。
1.简单阈值 使用的函数:cv2.threshold (src, thresh, maxval, type) 注释: 与名字一样,这种方法非常简单.但像素值高于阈值时,我们给这个像素赋予一个新值(可能 ...
- Notepad正则表达式用法
https://blog.csdn.net/cuckoo1/article/details/52165449
- centos7安全防护配置
前言 这段时间公司的服务器在做等保验证,对服务器的做了一些安全防护配置,留此记录. 操作系统版本:centos 7.6 密码有效周期 相关文件:/etc/login.defs 参数 说明 默认值 修改 ...
- UI获取元素的几种方式
通过浏览器驱动获取页面元素的8种方式. 定位方法: 通过webdriver对象的find_element方法 通过 id获取元素 el = driver.find_element(By.ID,'id' ...
- WPF --- 非Button自定义控件实现点击功能
引言 今天在做一个设置文件夹路径的功能,就是一个文本框,加个按钮,点击按钮,弹出 FolderBrowserDialog 再选择文件夹路径,简单做法,可以直接 StackPanel 横向放置一个 Te ...
- Qt安卓开发经验技巧总结V202308
01:01-05 pro中引入安卓拓展模块 QT += androidextras . pro中指定安卓打包目录 ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ...