众所周知,线段树可以在O( log n)的时间内进行很多修改和查询的操作,应用很广。

线段树,顾名思义,是一个二叉树,但是每个节点,存的不是不是“数”,而是一个“区间”,在百度百科中有非常容易理解的图片,一看就能理解线段树是怎么存在的。

线段树的存储方式和树的相似。

例如:有10 个数,那么,根节点的sum就是这10个数的和,lazy标记表示这十个数都要加上一个数,那么根节点的左二子就存的1—5的sum,lazy只是1—5范围的,右儿子表示6—10的,左二子的左二子是1—3,左二子的右儿子是2—5,右儿子的……以此类推,一直拆分到每个节点表示一个数的为止。

这道模板题主要用到了区间修改、单点修改和区间查询、单点查询(为了偷懒,我将单点修改、查询写成了查询、修改长度为 1 的区间……sorry)。

实现线段树的区间操作需要用到懒标记 lazy 数组,涉及到懒标记的下放(pushdown)和上传(pushup);

题意详见 Luogu 2357 守墓人;

下面在代码中对线段树进行分析:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<string>
  5 #include<cmath>
  6 #include<algorithm>
  7 using namespace std;
  8
  9 long long num[1000000];              //num数组存的是该节点的区间有多少个数,按理说这个是用不到的,          //但我菜 QAQ~ ,迫不得已又开了这个数组,下面会说……
 10 long long a[1000000],sum[1000000],n,f,lazy[1000000],m,l,r,k;//
 11 long long ans;          //a数组存的是该节点的数……          //sum存的线段树的节点表示的区间的值的和。          //lazy是懒标记,标记这个区间要加的数,因为“懒”,所以用不到时就一边待着……
 12
 13 void pushdown(int o){
 14     lazy[o*2+1]+=lazy[o];
 15     lazy[o*2]+=lazy[o];
 16     lazy[o]=0;
 17     return;
 18 }
 19          //下放函数,将该节点的懒标记,下放到左孩子和右孩子,自己的清零。 20 void pushup(int o){
 21     if(o==1) return;
 22     int p=o/2;
 23     sum[p]=sum[p*2]+sum[p*2+1]+lazy[p*2]*num[p*2]+lazy[p*2+1]*num[p*2+1];
 24     pushup(o/2);
 25 }
 26                //上传函数,因为子节点值出现修改,就沿着树向上修改父亲的值,一直修改到根节点。 27 long long build(int l,int r,int o){
 28     if(l>r) return 0;
 29     if(l==r){
 30         num[o]=1;
 31         sum[o]=a[l];
 32         return sum[o];    //如果拆分到不能再分,就把改点作为一个叶子节点,并返回值
 33     }else{
 34         num[o]=r-l+1;     //区间长度就是这个区间存在的数的个数。
 35         sum[o]=build(l,(l+r)/2,o*2)+build((l+r)/2+1,r,o*2+1);
 36         return sum[o];    //如果改点不是叶子节点,那么他的和就是左二子的+右儿子的。
 37     }
 38 }
 39
 40 void addn(int x,int y,int k,int o,int l,int r){ //加值函数
 41     int mid=(l+r)/2;
 42     if(x==l&&y==r){     //如果要修改的恰好为一个区间,就直接在区间上操作
 43         lazy[o]+=k;     //懒标记记录整个区间每个数要加的个数
 44         sum[o]+=lazy[o]*(r-l+1);  //sum记录整个区间加完数之后的值
 45         pushdown(o);   //下放标记
 46         pushup(o);     //上传值
 47         return;
 48     }else
 49     if(x>=mid+1&&y>=mid+1){   //如果要操作的都在区间中点的右边(右孩子),就到右孩子操作
 50         addn(x,y,k,o*2+1,mid+1,r);
 51     }else
 52     if(x<=mid&&y<=mid){  //如果要操作的都在区间中点的左边(左孩子),就到左孩子操作
 53         addn(x,y,k,o*2,l,mid);
 54     }else
 55     if(x<=mid&&y>=mid+1){    //如果该区间横跨左右两个孩子,就将该区间从中间劈开,分别处理
 56         addn(x,mid,k,o*2,l,mid);
 57         addn(mid+1,y,k,o*2+1,mid+1,r);
 58     }
 59 }
 60
 61 long long qiuh(int x,int y,int o,int l,int r){ //求和函数,原谅我不会 求和 的英语TUT
 62     int mid=(l+r)/2;
 63     if(x==l&&y==r) return (sum[o]+lazy[o]*(r-l+1));
 64     else
 65     if(x>=mid+1&&y>=mid+1){
 66         sum[o]+=lazy[o]*(r-l+1);
 67         pushdown(o);
 68         return (qiuh(x,y,o*2+1,mid+1,r));
 69     }
 70     else
 71     if(x<=mid&&y<=mid){
 72         sum[o]+=lazy[o]*(r-l+1);
 73         pushdown(o);
 74         return (qiuh(x,y,o*2,l,mid));
 75     }
 76     else
 77     if(x<=mid&&y>=mid+1){
 78         sum[o]+=lazy[o]*(r-l+1);
 79         pushdown(o);
 80         return qiuh(x,mid,o*2,l,mid)+qiuh(mid+1,y,o*2+1,mid+1,r);
 81     }
 82 }
 83 //求和函数的操作方式与加值函数几乎相同,看懂价值函数后很容易理解求和函数……
 84 int main(){
 85     scanf("%ld %ld",&n,&f);
 86     for(int i=1;i<=n;i++) scanf("%ld",&a[i]);
 87     build(1,n,1);
 88     for(int i=1;i<=f;i++){
 89         scanf("%ld",&m);
 90         switch (m){
 91             case 1:{
 92                 scanf("%ld %ld %ld",&l,&r,&k);
 93                 addn(l,r,k,1,1,n);
 94                 break;
 95             }
 96             case 2:{
 97                 scanf("%ld",&k);
 98                 addn(1,1,k,1,1,n);
 99                 break;
100             }
101             case 3:{
102                 scanf("%ld",&k);
103                 addn(1,1,k*(-1),1,1,n);
104                 break;
105             }
106             case 4:{
107                 scanf("%ld %ld",&l,&r);
108                 ans=qiuh(l,r,1,1,n);
109                 printf("%ld\n",ans);
110                 break;
111             }
112             case 5:{
113                 ans=qiuh(1,1,1,1,n);
114                 printf("%ld\n",ans);
115                 break;
116             }
117         }
118     }
119     return 0;
120 }

转载于:https://www.cnblogs.com/Misaki-Mei/p/7361614.html

线段树(区间修改)模板题 Luogu 2357 守墓人相关推荐

  1. 【模板】线段树区间修改

    区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v ...

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

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

  3. 线段树 区间更新模板

    一个带区间修改的线段树求和模板: int MAXN = 100005; ll a[100005<<2],ans,p; struct Tree {ll l,r;ll sum,add,mul; ...

  4. POJ 2777 Count Color (线段树区间修改 + 状态压缩)

    题目链接:POJ 2777 Count Color [题目大意] 给你 n 块板子, 编号1--n , 板子的颜色最多30种, 初始时  板子的颜色都是 1: 有两种操作 1 .把给定区间的板子染成一 ...

  5. HDU - 2871 Memory Control(线段树+区间合并)好题!

    题目链接:点击查看 题目大意:给定n个内存和m个操作,分别是: New x:从内存编号1开始向右查找,分配一个长度为x的空间,若找到输出区间的首地址,否则输出Reject New: Free x:释放 ...

  6. 【UOJ 53】线段树区间修改

    [题目描述]: 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 [输入描述]: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  7. HDU 1698 Just a Hook (线段树区间修改+区间查询)

    题目链接: 传送门 题意:Pudge对装备钩子进行若干次的强化,强化分为三种分别对应的价值是1,2,3,在经历过若干次操作后,输出钩子对应的总价值,每次强化都是对钩子进行区间修改 解题思路:在明白了题 ...

  8. hdu1698(线段树/区间修改/求和)

    hdu1698"Just a Hook" 题意: 有一个区间s [1,n],每一节si的初始价值为1.定义操作:x y val,将区间[x,y]中的每一个小节的价值改为val.问: ...

  9. 1631 小鲨鱼在51nod小学(线段树区间修改+单点查询:不用下传lazy的区间修改)

    题目描述: 1631 小鲨鱼在51nod小学 鲨鱼巨巨2.0(以下简称小鲨鱼)以优异的成绩考入了51nod小学.并依靠算法方面的特长,在班里担任了许多职务. 每一个职务都有一个起始时间A和结束时间B, ...

最新文章

  1. golang key map 所有_Golang面试知识点总结
  2. Linux安装配置Java1.8开发环境
  3. mysql5.5 配置_MySQL5.5 安装配置方法教程
  4. 用html和css布局如下图像,[看书][CSS精粹(第2版)]第三章 CSS和图像 HTML网页布局...
  5. K3CLOUD数据权限授权
  6. 第二百七十九节,MySQL数据库-pymysql模块操作数据库
  7. wrapper怎么用_用责任链模式设计拦截器
  8. [转载] java中数组的反射的探究
  9. mybatis实现代码自动生成
  10. linux dump备份svn,svnadmin dump+load库中的某个目录用svndumpfilter 可实现
  11. 华为手机刷机功能总结
  12. mysql中一个字符等于几个字节_细说一个汉字等于几个字符,以及汉字,字符,字节,位之间的关系...
  13. 博客园签名档图片圆角美化
  14. 算法-贪心/动态规划-买卖股票的最佳时机
  15. 2021 HTML面试题(最新)不定时更新
  16. 行测-图形推理-7-相异图形类
  17. SEO快速建站,八部曲
  18. 在线运行java测试
  19. 最近邻搜索|Nearest neighbor search
  20. 设置CentOS开机启动程序及定时关机

热门文章

  1. 论所谓“适合自己的方法”
  2. MySQL数据库学习(二)
  3. 2020年卫星行业研究报告
  4. 软件开发中的需求分析
  5. float 与 double 的区别
  6. HDFS Trash原理分析
  7. 河大计算机学院足球队,我校第二十九届“河大杯”足球赛落幕
  8. SEO从业者打造个人品牌的八个建议
  9. 西门子PLC产生随机数
  10. scala case语句中的中置表示法