线段树 懒标记 区间加一个简单的整数问题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的主要内容,如果未能解决你的问题,请参考以下文章