百度百科

Definition&Solution

  线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题。期望情况下,复杂度为O(nlogn)。

   核心思想见百度百科,线段树即将每个线段分成左右两个线段做左右子树。一个线段没有子树,当且仅当线段表示的区间为[a,a]。

   由于编号为k的节点的子节点为2k以及2k+1,线段树可以快速的递归左右叶节点。

   lazy标记:当进行区间修改的时候,如果一个区间整体全部被包含于要修改的区间,则可以将该区间的值修改后,将lazy标记打在区间上,不再递归左右区间。

   例如,要修改[15,30]区间整体+2,当前区间为[16,24],被包含于要修改的区间。记代表区间[16,24]的节点编号为k,则tree[k]+=2*(24-16+1),同时lazy[k]+=2。

   在下次修改或查询到k节点时,进行lazy的下放,即如下代码

inline void Free(cl l,cl r,cl p) {
    ll m=(l+r)>>,dp=p<<;
    tree[dp]+=(m-l+)*lazy[p];tree[dp+]+=(r-m)*lazy[p];
    lazy[dp]+=lazy[p];lazy[dp+]+=lazy[p];
    lazy[p]=;
}

   注意:被打上lazy标记的区间实际上已经修改完区间和,每次free修改的是子区间

Example

传送门

Description

已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

Input

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

Output

输出包含若干行整数,即为所有操作2的结果。

Sample Input


Sample Output


Hint

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

Solution

模板题。有一些需要注意的地方会在summary写明

Code

#include<cstdio>
#define maxn 100010
#define maxt 400010
#define ll long long int
#define cl const long long int

inline void qr(long long &x) {
    ;
    ')    {
        ;
        ch=getchar();
    }
    )+(x<<)+(ch^),ch=getchar();
    x*=f;
    return;
}

inline long long max(const long long &a,const long long &b) {if(a>b) return a;else return b;}
inline long long min(const long long &a,const long long &b) {if(a<b) return a;else return b;}
inline ) return x;else return -x;}

inline void swap(long long &a,long long &b) {
    long long c=a;a=b;b=c;return;
}

ll n,m,MU[maxn],sign,a,b,c;

ll tree[maxt],lazy[maxt];

void build(const ll l,const ll r,const ll p) {
    if(l>r)    return;
    if(l==r) {tree[p]=MU[l];return;}
    ll m=(l+r)>>,dp=p<<;
    build(l,m,dp);build(m+,r,dp+);
    tree[p]=tree[dp]+tree[dp+];
}

inline void Free(cl l,cl r,cl p) {
    ll m=(l+r)>>,dp=p<<;
    tree[dp]+=(m-l+)*lazy[p];tree[dp+]+=(r-m)*lazy[p];
    lazy[dp]+=lazy[p];lazy[dp+]+=lazy[p];
    lazy[p]=;
}

inline )*v;lazy[p]+=v;}

void add(cl l,cl r,cl p,cl aiml,cl aimr,cl v) {
    if(l>r) return;
    if(l>aimr||r<aiml) {return;}
    if(l>=aiml&&r<=aimr) {wohenlan(l,r,p,v);return;}
    Free(l,r,p);
    ll m=(l+r)>>,dp=p<<;
    add(l,m,dp,aiml,aimr,v);add(m+,r,dp+,aiml,aimr,v);
    tree[p]=tree[dp]+tree[dp+];
}

ll ask(cl l,cl r,cl p,cl aiml,cl aimr) {
    ;
    ;}
    if(l>=aiml&&r<=aimr) {return tree[p];}
    Free(l,r,p);
    ll m=(l+r)>>,dp=p<<;
    ,r,dp+,aiml,aimr);
}

int main() {
    qr(n);qr(m);
    ;i<=n;++i) qr(MU[i]);
    build(1ll,n,1ll);
    while(m--) {
        sign=a=b=;qr(sign);qr(a);qr(b);
        ) {
            c=;qr(c);
            add(,n,,a,b,c);
        }
        , n, , a, b));
    }
    ;
}

Summary

  1、线段树大小要开4*n。理论上线段树会有2*n个子节点,但是试试这棵线段树:1 2 3 4 5

      如图所示:

         可以看到,节点数确实是6*2-1=11个,但是由于我们每个节点编号都严格按照母节点*2(+1)进行编号,所以我们的编号开到了2*n之外。开4*n是比较保险的。

    2、注意对lazy标记的free操作要在确定区间可以再分以后进行。即先写

if(l>=aiml&&r<=aimr) {wohenlan(l,r,p,v);return;}

      或

if(l>=aiml&&r<=aimr) {return tree[p];}

      后,如果没有return,则证明区间一定是可再分的,即还没有递归到叶节点,这时才可以进行free操作。否则的话考虑在叶节点的编号可能大于2*n,我们在叶节点free了一下,标记被下放到了4*n以外……

      然后你就炸了。

【线段树】【P3372】模板-线段树的更多相关文章

  1. 【数据结构与算法】Trie(前缀树)模板和例题

    Trie 树的模板 Trie 树的简介 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树.他的核心思想是空间换 ...

  2. hdu 1754 I Hate It (模板线段树)

    http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others)    M ...

  3. hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询

    点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...

  4. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  5. LuoguP3834 【模板】可持久化线段树 1(主席树)|| 离散化

    题目:[模板]可持久化线段树 1(主席树) 不知道说啥. #include<cstdio> #include<cstring> #include<iostream> ...

  6. 【洛谷P3834】(模板)可持久化线段树 1(主席树)

    [模板]可持久化线段树 1(主席树) https://www.luogu.org/problemnew/show/P3834 主席树支持历史查询,空间复杂度为O(nlogn),需要动态开点 本题用一个 ...

  7. Pascal 线段树 lazy-tag 模板

    先说下我的代码风格(很丑,勿喷) maxn表示最大空间的四倍 tree数组表示求和的线段树 delta表示增减的增量标记 sign表示覆盖的标记 delta,sign实际上都是lazy标志 pushd ...

  8. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  9. 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]

    题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...

随机推荐

  1. Selenium(Python)页面对象+数据驱动测试框架

    整个工程的目录结构: 常用方法类: class SeleniumMethod(object): # 封装Selenium常用方法 def __init__(self, driver): self.dr ...

  2. SQL Sever查询语句集锦

    一. 简单查询简单的Transact-SQL查询只包括选择列表.FROM子句和WHERE子句.它们分别说明所查询列.查询的表或视图.以及搜索条件等. 例如,下面的语句查询testtable表中姓名为“ ...

  3. 在Arch上安装VSCode的方法

    首先去特硬去下载vscode的安装包 mkdir /tmp/vscode cd /tmp/vscode/ wget https://az764295.vo.msecnd.net/public/0.3. ...

  4. Github协作图想

    首先 git pull 从远程拉下代码,并在本地与本地代码自动合并 在本地解决冲突后,可将本地代码进行远程推送 版本库的Repository中存储的是版本树状链,每一根链接线代表每一次的修改,每一个节 ...

  5. spark-submit配置说明

    <Spark 官方文档>Spark配置 spark-1.6.0 原文地址 Spark配置 Spark有以下三种方式修改配置: Spark properties (Spark属性)可以控制绝 ...

  6. 使用js跳转手机站url的若干注意点

    引子: 去年年底公司开发手机站平台,经历了前期的用户群.市场调查,产品需求分析,产品原型设计,ui前端到程序开发上线测试等等工作,终于上线...此处略去本人作为前端开发的心情. 应该说,我们的手机站平 ...

  7. kafka stream 低级别的Processor API动态生成拓扑图

    public class KafkaSream { public static void main(String[] args) { Map<String, Object> props = ...

  8. 使用树莓派实现(山寨)高清视频叠加(HDMI OSD)

    项目需要在HDMI上叠加一些字符包括汉字和数值,要求不能使用台式机,本身也没有HDMI采集卡驱动开发能力,所以通过海思的HDMI编码器将HDMI编码为h.264网络视频流,然后通过树莓派解码显示,做字 ...

  9. c++SDK c#调用_疑难杂症

    在编写过程中,会不时遇到各种问题: 1.dll明显在和exe同一目录下但调用不成功, 2.运行正常,没有报错,参数数值运行过程中也一致,但结果就是达不到预想, 都是dll没有引用完全造成的影响. 推荐 ...

  10. lintcode-187-加油站

    187-加油站 在一条环路上有 N 个加油站,其中第 i 个加油站有汽油gas[i],并且从第_i_个加油站前往第_i_+1个加油站需要消耗汽油cost[i]. 你有一辆油箱容量无限大的汽车,现在要从 ...