带有lazy标记的线段树

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,val,com,s[100000];
struct st{
    int l,r,val,add;
}tr[10000000];
void build(int l,int r,int k)
{
    tr[k].l=l;
    tr[k].r=r;
    if(l==r)
    {
        tr[k].val=s[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tr[k].val = tr[k<<1].val + tr[k<<1|1].val;
}
void pus(int k)
{
    int l=tr[k].l;
    int r=tr[k].r;
    tr[k].add+=tr[k>>1].add;
    tr[k].val+=(r-l+1)*tr[k>>1].add;
}
void update(int x,int y,int k,int val)
{
    if(tr[k].add)
    {
        pus(k<<1);
        pus(k<<1|1);
        tr[k].add=0;
    }
    int l=tr[k].l;
    int r=tr[k].r;
    int mid=(l+r)>>1;
    if(y<l || x>r)
        return;
    if(x<=l && r<=y)
    {
        tr[k].val += (l-r+1)*val;
        tr[k].add += val;
        return;
    }
    else
    {
        if(x<=mid)
            update(x,y,k<<1,val);
        if(y>mid)
            update(x,y,k<<1|1,val);
        tr[k].val = tr[k<<1].val + tr[k<<1|1].val;
    }
}
int sum(int x,int y,int k)
{
    if(tr[k].add)
    {
        pus(k<<1);
        pus(k<<1|1);
        tr[k].add=0;
    }
    int l=tr[k].l;
    int r=tr[k].r;
    int mid=(l+r)>>1;
    if(y<l || x>r)
        return 0;
    if(x<=l && r<=y)
        return tr[k].val;
    else
    {
        int ans=0;
        if(x<=mid)
            ans+=sum(x,y,k<<1);
        if(y>mid)
            ans+=sum(x,y,k<<1|1);
        return ans;
    }
}
main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&s[i]);
    build(1,n,1);
    while(m--)
    {
        scanf("%d",&com);
        if(com==1)
        {
            scanf("%d%d%d",&x,&y,&val);
            update(x,y,1,val);
        }
        else
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",sum(x,y,1));
        }
    }
}
时间: 2024-10-10 00:17:14

带有lazy标记的线段树的相关文章

HDU1698 just a Hook - 带有lazy标记的线段树

2017-08-30 16:44:33 writer:pprp 上午刚刚复习了一下不带有lazy标记的线段树, 下午开始学带有lazy标记的线段树 这个是我看大佬代码敲的,但是出了很多问题, 这提醒我: 1.要注意边界条件,一个边界条件的取等或者不取等,小于或者大于出错的话就直接运行不了了 2.注意输入输出,经过多次测试,果然还是用scanf比较保险,试了试用fast_io的cin结果还是TLE 所以以后不要用cin了,cin害人啊,两个混用就更加麻烦了 这个题就是区间修改,区间查询的一道题,但

区改区查标记永久化线段树

写完树剖之后发现还没有讲过区改区查线段树... 标记永久化线段树的用处: 支持区改区查,嗯,就这样.(不过听很多dalao说这种线段树有利于写主席树) 算法核心思路: 对于一段区间加,假如它把线段树上的一部分完全包涵,那么我们就把它“永久”的加在这部分上,否则就加在另外一个神奇的地方,这个神奇的地方只有当询问区间将其完全包涵才能加. 这样我们就把区间加变成了log级别的. 代码实现: procedure update(k,l,r,x,y,z:longint); var mid:longint;

[HDU5306]Gorgeous Sequence(标记回收线段树)

题意:维护一个序列,支持区间与一个数取min,询问区间最大,询问区间和(序列长度<=1e6) 分析: http://www.shuizilong.com/house/archives/hdu-5306-gorgeous-sequence/?variant=zh-cn 在建树的时候,就已经生成了lazy标记,具体的参加jry的16年集训队论文 这样使得lazy标记有了这一样一个性质:子节点向上走碰到的第一个lazy的值就是此节点的值 打标记操作: 标记回收操作:

[hdoj4578][多延迟标记的线段树]

Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)Total Submission(s): 9392    Accepted Submission(s): 2408 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2

洛谷 P3372 【模板】线段树 1

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=3372 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下

hihocoder1080线段树+区间修改+区间查询+多个懒标记

题目链接:http://hihocoder.com/problemset/problem/1080 对于这种不止一个懒标记的线段树,只要弄清楚各种操作和各种懒标记间的关系就OK了. 我的代码: 1 #include <cstdio> 2 3 using namespace std; 4 5 #define MAXN 100005 6 7 int p[MAXN]; 8 9 struct segNode 10 { 11 int left, right, sum, dd, vv; 12 bool l

《数据结构》线段树入门(二)

今天继续介绍——线段树之延迟标记 接上期<数据结构>线段树入门(一):http://www.cnblogs.com/shadowland/p/5870339.html 在上期介绍了线段树的最基本内容(线段树单点修改,区间查询),这次将介绍:区间修改,区间查询. Question: 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述: 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,每行表示操作的个数,如果第一数是1,后接3个正

[知识点]线段树

// 此博文为迁移而来,写于2015年3月30日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vw6j.html 1.前言 一道题目:给出一个一维数组共n个结点,每次对他进行一些操作:在[l,r]范围内增加x,或是询问第i个结点当前的值为多少.这不水题嘛!直接模拟就可以了.但是如果n<=100000呢?询问次数超过100000呢?O(n^2)并不能扛住.今天要引入的内容就是线段树.这东西很早之前有提到过,我也编过,但

线段树 入门详解

概念(copy度娘): 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩. 通俗地讲: 线段树就是把一个线段转变为一个二叉树,如下所示: 一个线段长度为4,则把它变成线段树,就是这个样子 这样如果你想改变一个区间的值,只用O(logn).比一般算法快了许多. 但是空间复杂度就会高一些,比如本来