[Luogu 3372] Line Segment Tree Template (lazy Marker)

lazy thought:
For example, when we want to add C to [a,b] interval, we find an interval which is included by [a,b] interval, then sum + = c* (edge [i], R - edge [i], L + 1) of this interval, and label this interval lazy. If normal practice should be to increase the interval of the interval c, but lazy marker is to return directly, not to update the sum of the interval, when the next need to use the value of the interval, then update again, thus avoiding a lot of useless operations.

Structural Definition:

struct node{
   ll lazy,pre;    //Lazy stands for lazy markers, pre stands for intervals and
   int l,r;        //Interval boundary
}edge[maxn*4];    

Tree Building Code:

void build(int p,int l,int r)
{
    edge[p].l=l,edge[p].r=r;
    if(l == r){
        edge[p].pre=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    edge[p].pre=edge[p<<1].pre+edge[p<<1|1].pre;
}

Update the interval code:
The lazy tag is mainly used here.

void change(int p,int x,int y,ll z)
{
    if(edge[p].l >= x && edge[p].r <= y){       //If the interval is overwritten, change its value
        edge[p].lazy+=z;
        edge[p].pre += z*(ll)(edge[p].r-edge[p].l+1);
        return ;
    }
    spread(p);       //The interval is uncovered and the lazy marker is lowered. At this time, the subinterval of the interval is not updated.
    int mid=(edge[p].l+edge[p].r)>>1;
    if(x <= mid)
        change(p<<1,x,y,z);     //If the interval to be modified covers the left son, update the left son
    if(mid <y)      //Cover the right son, update the right son
        change(p<<1|1,x,y,z);
    edge[p].pre=edge[p<<1].pre+edge[p<<1|1].pre;   //Maintenance value = left son + right son
    return ;
}

Here, when the interval is overwritten, it return s after the update, instead of continuing to update the sub-interval, which is the idea of lazy markup.
When will the value of the child node be updated again?
When the interval is not covered, the sub-interval is accessed. At this time, the lazy marker is lowered to the sub-interval, and the value of edge[i].pre and lazy are updated.

void spread(int p)
{
    if(edge[p].lazy){
        edge[p<<1].lazy+=edge[p].lazy;
        edge[p<<1|1].lazy+=edge[p].lazy;
        edge[p<<1].pre+=edge[p].lazy*(ll)(edge[p<<1].r-edge[p<<1].l+1);
        edge[p<<1|1].pre+=edge[p].lazy*(ll)(edge[p<<1|1].r-edge[p<<1|1].l+1);
        edge[p].lazy=0;     //lazy is assigned a value of 0 after decentralization
    }
}

Here is the code for finding the sum of intervals:

void ask(int p,ll x,ll y)
{
    if(edge[p].l >= x && edge[p].r <=y){     //If the interval is completely covered, add the interval sum directly.
       ans+=edge[p].pre;
       return ;
    }
    spread(p);          //Uncovered still lowered markers
    int mid = (edge[p].l+edge[p].r)>>1;
    if(x <= mid)
        ask(p<<1,x,y);
    if(mid < y)
        ask(p<<1|1,x,y);
}

Here is the AC code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
#define memset(a,b) memset(a,b,sizeof(a))
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000000007
const int maxn=1e6+10;

ll a[maxn];
struct node{
   ll lazy,pre;
   int l,r;
}edge[maxn*4];
ll ans;

void build(int p,int l,int r)
{
    edge[p].l=l,edge[p].r=r;
    if(l == r){
        edge[p].pre=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    edge[p].pre=edge[p<<1].pre+edge[p<<1|1].pre;
}
void spread(int p)
{
    if(edge[p].lazy){
        edge[p<<1].lazy+=edge[p].lazy;
        edge[p<<1|1].lazy+=edge[p].lazy;
        edge[p<<1].pre+=edge[p].lazy*(ll)(edge[p<<1].r-edge[p<<1].l+1);
        edge[p<<1|1].pre+=edge[p].lazy*(ll)(edge[p<<1|1].r-edge[p<<1|1].l+1);
        edge[p].lazy=0;
    }
}
void change(int p,int x,int y,ll z)
{
    if(edge[p].l >= x && edge[p].r <= y){
        edge[p].lazy+=z;
        edge[p].pre += z*(ll)(edge[p].r-edge[p].l+1);
        return ;
    }
    spread(p);
    int mid=(edge[p].l+edge[p].r)>>1;
    if(x <= mid)
        change(p<<1,x,y,z);
    if(mid <y)
        change(p<<1|1,x,y,z);
    edge[p].pre=edge[p<<1].pre+edge[p<<1|1].pre;
    return ;
}
void ask(int p,ll x,ll y)
{
    if(edge[p].l >= x && edge[p].r <=y){
       ans+=edge[p].pre;
       return ;
    }
    spread(p);
    int mid = (edge[p].l+edge[p].r)>>1;
    if(x <= mid)
        ask(p<<1,x,y);
    if(mid < y)
        ask(p<<1|1,x,y);
}
int main()
{
    int n,m,op,x,y;
    ll k;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    build(1,1,n);

    for(int i=1;i<=m;i++){
        scanf("%d",&op);
        ans=0;
        if(op == 1){
            scanf("%d %d %lld",&x,&y,&k);
            change(1,x,y,k);
        }
        else{
            scanf("%d %d",&x,&y);
            ask(1,x,y);
            printf("%lld\n",ans);
        }
    }

    return 0;
}

Added by highrevhosting on Thu, 10 Oct 2019 02:26:52 +0300