线段树是一种基于分治思想的二叉树,每一个结点都对应一个区间,叶子节点的区间L=R,非叶子结点,左孩子区间为**[L,(L+R)/2],右孩子区间为[(L+R)/2+1,R].所以和树状数组相比,线段树能更好的维护一个区间= =这也是其优势所在
那么对于每一个结点,我们可以维护什么信息呢?
区间的最值,区间和等等,具体根据题目的要求来确定;
以下代码和示例均维护区间最值(最大值);
以下是一些常用的操作,代码块里均有实现方式
图源@bilibili 算法训练营



看到这可能就有疑问了,线段树的最大作用不是维护一个区间吗,这里除了区间查询并没有区间更新的操作。那么假设我们要对某个区间[L,R]上的所有元素都加减某个元素v,如果按照点更新的方式,毫无疑问时间复杂度为nlogn,这个时间复杂度是很不理想的,于是下面引入懒标记(Lazy_tag)**;
对于某个区间操作,因为后面的操作不一定会涉及这个区间的子区间,所以我们不妨懒一点,既然没有查询,那么这次区间操作我并没有必要更新所有的子区间,我只更新最大的那个,并且标记一下,代表这个区间是进行过操作的就行,等到下次操作要用到这个区间我们再对子区间进行更新。这样的话,区间更新的时间复杂度可以近似为O(logn),这是很理想的;
大家可以自行查阅文章

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
const int INF=0x3f3f3f3f;
int n,a[N];
struct node
{int l,r,mx;//左右端点以及最值   这里也可以换成区间值,根据需求就行int lazy_tag;//懒惰标记;
}tree[N*4];//一定要开4倍n空间;
void f(int k,int lazy_tag)
{tree[k].lazy_tag+=lazy_tag;tree[k].mx+=lazy_tag;
}
void pushdown(int k)//懒惰标记下传
{f(k*2,tree[k].lazy_tag);f(k*2+1,tree[k].lazy_tag);tree[k].lazy_tag=0;//懒惰标记置零
}
void build(int k,int l,int r)//递归建立线段树,k表示存储下标;
{tree[k].l=l;tree[k].r=r;if(l==r)//递归出口 {tree[k].mx=a[l];//最值就是a[l]存储的值 return;}int mid=l+r>>1;build(k*2,l,mid);build(k*2+1,mid+1,r);tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx);//当前区间最值即为左右孩子的最值;
}
void push(int k,int l,int r,int v)//区间更新,区间加减v
{if(tree[k].l>=l&&tree[k].r<=r)//如果区间被覆盖 {tree[k].mx+=v;tree[k].lazy_tag=v;//打上懒惰标记 return;}pushdown(k);int mid=(tree[k].l+tree[k].r)>>1;if(l<=mid)push(k*2,l,r,v);if(r>mid)push(k*2+1,l,r,v);tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx);
}
void update(int k,int i,int v)//点更新,将a[i]修改更新为v,并维护线段树
{if(tree[k].l==tree[k].r&&tree[k].l==i)//如果是叶子结点而且l=i; {tree[k].mx=v;return;}int mid=(tree[k].l+tree[k].r)/2; if(i<=mid)//在左子树update(k*2,i,v);elseupdate(k*2+1,i,v);tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx);//回归时更新最值维护线段树;
}
int query1(int k,int l,int r)//用区间覆盖的方法 查询区间l-r的最值 (l,r)不改变;
{if(tree[k].l>=l&&tree[k].r<=r)//区间覆盖return tree[k].mx;if(tree[k].lazy_tag)//先下传懒惰标记 pushdown(k);int mid=(tree[k].l+tree[k].r)/2;int Max=-INF;//负无穷 if(l<=mid)Max=max(Max,query1(k*2,l,r));if(r>mid)Max=max(Max,query1(k*2+1,l,r));return Max;
}
int query2(int k,int l,int r)//区间相等查询l-r的最值  (l,r)改变
{if(tree[k].l==l&&tree[k].r==r)return tree[k].mx;if(tree[k].lazy_tag)//先下传懒惰标记 pushdown(k);int mid=(tree[k].l+tree[k].r)/2;if(r<=mid)//左子树查询 return query2(k*2,l,r);else if(l>mid)return query2(k*2+1,l,r);elsereturn max(query2(k*2,l,mid),query2(k*2+1,mid+1,r));//左右子树分别查询缩小范围
}
void print(int k)
{if(tree[k].mx){cout<<k<<" "<<tree[k].l<<" "<<tree[k].r<<" "<<tree[k].mx<<endl;print(k*2);print(k*2+1);}
}
int main()
{cin>>n;for(int i=1;i<=n;i++)cin>>a[i];build(1,1,n);int l,r,v,i;cin>>l>>r;cout<<query1(1,l,r)<<endl;cout<<query2(1,l,r)<<endl;cin>>i>>v;update(1,i,v);cout<<query1(1,l,r)<<endl;cout<<query2(1,l,r)<<endl;push(1,l,r,v);cout<<query1(1,l,r)<<endl;cout<<query2(1,l,r)<<endl;cin>>l>>r;cout<<query1(1,l,r)<<endl;cout<<query2(1,l,r)<<endl;return 0;
}

线段树的简单实现(引入lazy_tag)相关推荐

  1. [CQOI 2006]线段树之简单题

    Description 有一个n个元素的数组,每个元素初始均为0.有m条指令,要么让其中一段连续序列数字反转--0变1,1变0(操作1),要么询问某个元素的值(操作2).例如当n=20时,10条指令如 ...

  2. 线段树3——一些例题的题解

    这篇博客主要是由一些题目的题解构成的 1.XOR的艺术 https://www.luogu.org/problemnew/show/P2574 本题就是一个线段树的简单变形,把懒标记改成异或值就行了. ...

  3. 2018年6月2号(线段树(2))

    昨天只是普通的线段树(简单的单点修改) 而今天将讲是比较普通的简单的区间修改(加法修改): 我主要是复制代码的蒟蒻我只能依靠模板为生,所以我想特地练下手: 1 #include<bits/std ...

  4. (转)线段树的区间更新

    原文地址:http://blog.csdn.net/zip_fan/article/details/46775633 写的很好,昨天刚刚开始写线段树,有些地方还不是很明白,看了这篇博文,学会了数组形式 ...

  5. [矩形并-扫描线-线段树]Picture

    最近在补数学和几何,没啥好写的,因为已经决定每天至少写一篇了,今天随便拿个题水水. 题目大意:给你N个边平行于坐标轴的矩形,求它们并的周长.(N<=5000) 思路:这个数据范围瞎暴力就过了,但 ...

  6. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  7. 公园遛狗 / 小白逛公园【线段树】

    >Link ybtoj公园遛狗 luogu P4513 >解题思路 这道题我做的时候只想到了build.insert怎么写,ask看了书以后写的(真的好巧妙T) 单点修改+区间查询使我们想 ...

  8. 线段树入门之夜空星亮

    --------------------------------------------不是能不能办到的问题,既然我已经下定决心要成为海贼王了,如果因此而战死的话,也无所谓了. 承接上一章节,继续探索 ...

  9. P1253 [yLOI2018] 扶苏的问题 (线段树)

    原题链接:[yLOI2018] 扶苏的问题 - 洛谷 思路: 1.其实就是用线段树进行简单的区间修改(每个数修改为x, 每个数加x)和区间查询.因为有两种区间修改,所以分别用upd和add数组来标记: ...

  10. UVA11992(线段树)

    题目 题意 road命令连接第A坐标和第B坐标的点.而line则是查看纵坐标C拉出的扫描线过几个联通块,要求求联通块中的数量和是多少.(具体的可以查看原题) 题解 其实是线段树一个简单的模拟,即并查集 ...

最新文章

  1. Nreal招聘|SLAM、深度学习、服务器开发工程师等岗位(校招/社招)
  2. 2015年12月流量入口占比动态:仅直接访问实现上涨
  3. 为什么数据中心不能给乡镇带来新的就业机会
  4. [BZOJ1984] 月下“毛景树”
  5. 容易被误读的IOSTAT
  6. Matalab类定义
  7. ejb jsf jpa_完整的WebApplication JSF EJB JPA JAAS –第2部分
  8. centos升级之共享文件夹
  9. Spark IDEA 编程环境配置
  10. 【LeetCode笔记】剑指Offer 43. 1~n 整数中1出现的次数(Java、数位dp、偏数学)
  11. spark学习-50-Spark的stage的划分
  12. mysql扫盲篇_MySQL小白扫盲(一)
  13. win7 电脑MAC地址修改
  14. 【小程序源码】uni-app云开发的网盘助手抓取网盘资源
  15. sql 语句中count()有条件的时候为什么要加上or null
  16. 网页设计-公用导航栏
  17. 【Unity+MySQL】实现简单的注册登录系统
  18. 关于3D打印材料及发展方向分析
  19. SAR-Scape处理SBAS-InSAR报错原因之一
  20. python装饰器模式带参数_python函数装饰器、类装饰器和带参数的装饰器——装饰器模式...

热门文章

  1. css 设置背景颜色渐变
  2. Java学习:Java程序员必读的经典书籍没有之一,你读过几本?
  3. xenu死链接工具使用
  4. gradle命令中api和implement的区别
  5. 基因测序技术发展历史以及一、二、三代测序技术原理及应用
  6. 黑客郭盛华虚假新闻_每日新闻摘要:黑客闯入十个电信网络
  7. 天翼网关 ddns设置_为什么说网关在任何工业物联网解决方案中都很重要?
  8. RouterOS(ROS)设置动态域名(DDNS)
  9. 使用python来搭建一个简易的文件下载环境以及用droopy来实现一个文件上传环境
  10. ubuntu11.04(unix 就可以了) 共享文件以及支持上传文件