题目链接:
题解思路:
题目中对区间修改有两个操作:
0 区间所有点增加v
1 区间所有点改为v
容易想到应该使用到两个懒惰标记 一个记录替换 一个记录增减
但这里会涉及到一个顺序问题 ,这里就需要考虑到 懒惰标记传递的策略:
如果出现替换标记 就应该把增减标记覆盖
如果同区间出现多个增减标记 则需要将标记叠加
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 100050
using namespace std;
int w[maxn<<2];
int tag[maxn<<2][2]= {0};
void push_up(int rt)
{
w[rt]=w[rt<<1]+w[rt<<1|1];
}
void push_down(int rt,int len)
{
if(tag[rt][1]) //替换标记
{
tag[rt<<1][1]=tag[rt<<1|1][1]=tag[rt][1];
tag[rt<<1][0]=tag[rt<<1|1][0]=0; //子节点的增减标记清0
w[rt<<1]=(len-(len>>1))*tag[rt][1];
w[rt<<1|1]=(len>>1)*tag[rt][1];
tag[rt][1]=0;
}
if(tag[rt][0]) //增减标记
{
tag[rt<<1][0]+=tag[rt][0]; //叠加 是+=不是=!!!
tag[rt<<1|1][0]+=tag[rt][0]; //叠加
w[rt<<1]+=(len-(len>>1))*tag[rt][0];
w[rt<<1|1]+=(len>>1)*tag[rt][0];
tag[rt][0]=0;
}
}
void build(int l,int r,int rt)
{
if(l==r)
scanf("%d",&w[rt]);
else
{
int m=(l+r)>>1;
build(lson);
build(rson);
push_up(rt);
}
}
void update(int op,int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
if(op){
w[rt]=(r-l+1)*v;
tag[rt][1]=v;
tag[rt][0]=0; //增减标记清0
}
else
{
w[rt]+=(r-l+1)*v; //叠加
tag[rt][0]+=v;
}
return ;
}
push_down(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update(op,L,R,v,lson);
if(R>m)
update(op,L,R,v,rson);
push_up(rt);
}
int main()
{
int n,q,op,l,r,v;
scanf("%d%d",&n,&q);
build(0,n,1);
while(q--)
{
scanf("%d%d%d%d",&op,&l,&r,&v);
update(op,l,r,v,0,n,1);
printf("%d\n",w[1]);
}
return 0;
}