线段树 懒标记 区间加一个简单的整数问题2

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 懒标记 区间加一个简单的整数问题2相关的知识,希望对你有一定的参考价值。

【线段树 懒标记】一个简单的整数问题2

题目

在这里插入图片描述

思路

感觉还是蓝书上的解析比较容易懂
首先考虑维护信息。
sum:如果考虑当前节点及子节点上的所有标记,当前区间和是多少(不考虑所有祖先节点标记)
add(增量延迟标记):给当前区间的所有儿子加上add(不包括自己)

struct  Node{
	int l,r;
	LL sum,add;
}tr[N*4]

延迟标记的含义是:该节点曾经被修改但其子节点尚未被更新,也就是说如果存在延迟标记,那就是子节点待更新并且它自身保存的信息应该已经被修改完了。
主要看注释吧

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e5+10;
int n,m;
LL w[N];
struct Node{
    int l,r;
    LL sum,add;
}tr[N*4];
/*维护更新信息*/
void pushup(Node &u,Node &l,Node &r){
    u.sum=l.sum+r.sum;
}

void pushup(int u){
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}

void pushdown(int u){
    auto &root=tr[u],&left=tr[u<<1],&right=tr[u<<1|1];
    if(root.add){//如果存在延迟标记
        left.sum+=(LL)(left.r-left.l+1)*root.add;//更新左节点信息
        right.sum+=(LL)(right.r-right.l+1)*root.add;//更新右节点信息
        left.add+=root.add;//给左节点打延迟标记
        right.add+=root.add;//给右节点打延迟标记
        root.add=0;//清空父节点延迟标记
    }
}
void build(int u, int l, int r)
{
    if (l == r) tr[u] = {l, r, w[r], 0};
    else
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void modify(int u,int l,int r,int d){
    if(tr[u].l>=l&&tr[u].r<=r){//完全覆盖
        tr[u].sum+=(LL)(tr[u].r-tr[u].l+1)*d;//更新节点信息
        tr[u].add+=d;//给节点打上标记
    }
    else{
        pushdown(u);//下传延迟标记
        int mid=(tr[u].l+tr[u].r)>>1;
        if(l<=mid)modify(u<<1,l,r,d);
        if(r>mid)modify(u<<1|1,l,r,d);
        pushup(u);//更新节点信息
    }
}

LL query(int u,int l,int r){
    if( tr[u].l >= l && tr[u].r <= r)return tr[u].sum;//区间被包含
    pushdown(u);//下传延迟标记
    int mid=(tr[u].l+tr[u].r)>>1;
    LL sum=0;
    if(l<=mid)sum=query(u<<1,l,r);
    if(r>mid)sum+=query(u<<1|1,l,r);
    return sum;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
    build(1,1,n);
    
    char op[2];
    int l,r,d;
    while(m--){
        scanf("%s%d%d",op,&l,&r);
        if(*op=='C'){
            scanf("%d",&d);
            modify(1,l,r,d);
        }
        else printf("%lld\\n",query(1,l,r));
    }
    return 0;
}

以上是关于线段树 懒标记 区间加一个简单的整数问题2的主要内容,如果未能解决你的问题,请参考以下文章

线段树区间修改区间求和

[模板]洛谷T3373 线段树 模板2

线段树

一般线段树与权值线段树

线段树---区间修改

「ZJOI2019」线段树