您的位置:首页 > 其它

线段树区间修改之双标记 【lazy两重标记并且分类讨论】

2017-07-26 18:19 579 查看
//前面说了单标记的, 那如果都有了? 这个时候就要用双标记了, 并且讨论下之前标记的情况.

板子题

模板 :

const int maxn = 1e5+5;
int cas=1;
ll a[maxn];
struct node{
int tl, tr; ll val, lazyset,lazyadd;
void funset(ll tmp1,ll tmp2) {
lazyset = tmp1;
lazyadd = tmp2;
ll tmp = tmp1 + tmp2;
val = (tr - tl + 1) * tmp;
}
void funadd(ll tmp) {
lazyadd += tmp;
val += (tr - tl + 1) * tmp;
}
} tree[maxn*4];

void pushup(int id)
{
tree[id].val = tree[id<<1].val+tree[id<<1|1].val;
}

void pushdown(int id)
{
if(tree[id].lazyset){
tree[id<<1].funset(tree[id].lazyset,tree[id].lazyadd);
tree[id<<1|1].funset(tree[id].lazyset,tree[id].lazyadd);
tree[id].lazyset = 0;
tree[id].lazyadd = 0;
}
else if(tree[id].lazyadd){
tree[id<<1].funadd(tree[id].lazyadd);
tree[id<<1|1].funadd(tree[id].lazyadd);
tree[id].lazyadd = 0;
}
}

void build(int id,int l,int r)
{
tree[id].tl = l; tree[id].tr = r; tree[id].lazyset = tree[id].lazyadd = 0;
if(l == r){
tree[id].val = a[l];
return ;
}
int mid = (l+r) >> 1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}

void update(int id,int st,int ed,int val,int flag)
{
int l=tree[id].tl, r=tree[id].tr;
//printf("%d %d %d %d %d\n",id,l,r,st,ed);
if(st <= l && r <= ed){
if(flag) tree[id].funset(val,0);
else tree[id].funadd(val);
return ;
}
pushdown(id);
int mid = (l+r) >> 1;
if(st <= mid) update(id<<1,st,ed,val,flag);
if(ed > mid) update(id<<1|1,st,ed,val,flag);
pushup(id);
}

ll query(int id,int ql,int qr)
{
int l = tree[id].tl , r = tree[id].tr;
if(ql <= l && r <= qr) return tree[id].val;
pushdown(id);
int mid = (l+r) >> 1 ,res1=0,res2=0;
if(ql <= mid) res1 += query(id*2,ql,qr);
if(qr > mid) res2 += query(id*2+1,ql,qr);
return (res1 + res2);
}

void solve()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n+1;i++){
scanf("%d",&a[i]);
}
build(1,1,n+1);
while(q--){
int a,b,c,w;
scanf("%d%d%d%d",&a,&b,&c,&w);
b++; c++;
if(a == 0) update(1,b,c,w,a);
else update(1,b,c,w,a);
printf("%d\n",query(1,1,n+1));
}
}


//注意下标从0开始的.

解释版:

/** @Cain*/
const int maxn = 1e5+5;
int cas=1;
ll a[maxn];
struct node{
int tl, tr; ll val, lazyset,lazyadd;
//双标记啊, add为负就是减呗.
void funset(ll tmp1,ll tmp2) {
lazyset = tmp1;
lazyadd = tmp2;
ll tmp = tmp1 + tmp2;
val = (tr - tl + 1) * tmp;
}
void funadd(ll tmp) {
lazyadd += tmp;
val += (tr - tl + 1) * tmp;
}
} tree[maxn*4];

void pushup(int id)
{
tree[id].val = tree[id<<1].val+tree[id<<1|1].val;
}

void pushdown(int id)
{
if(tree[id].lazyset){   //标记之间有个优先级
//如果当前这个区间有set标记,那么往下更新的val值是add和set的和. add=0也不影响.
tree[id<<1].funset(tree[id].lazyset,tree[id].lazyadd);
tree[id<<1|1].funset(tree[id].lazyset,tree[id].lazyadd);
//因为有set时, 明显下方有什么都会被直接覆盖!,所以是求的set和add的和.
tree[id].lazyset = 0;
tree[id].lazyadd = 0;
}
else if(tree[id].lazyadd){  //然后再单独讨论add标记.
tree[id<<1].funadd(tree[id].lazyadd);
tree[id<<1|1].funadd(tree[id].lazyadd);
tree[id].lazyadd = 0;
}
}

void build(int id,int l,int r)
{
tree[id].tl = l; tree[id].tr = r; tree[id].lazyset = tree[id].lazyadd = 0;
if(l == r){
tree[id].val = a[l];
return ;
}
int mid = (l+r) >> 1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}

void update(int id,int st,int ed,int val,int flag)
{
int l=tree[id].tl, r=tree[id].tr;
//printf("%d %d %d %d %d\n",id,l,r,st,ed);
if(st <= l && r <= ed){
if(flag) tree[id].funset(val,0);
//如果放下set标记,则add标记就没有什么用了,所以直接清空.
else tree[id].funadd(val);
return ;
}
pushdown(id);
int mid = (l+r) >> 1;
if(st <= mid) update(id<<1,st,ed,val,flag);
if(ed > mid) update(id<<1|1,st,ed,val,flag);
pushup(id);
}

ll query(int id,int ql,int qr)
{
int l = tree[id].tl , r = tree[id].tr;
if(ql <= l && r <= qr) return tree[id].val;
pushdown(id);
int mid = (l+r) >> 1 ,res1=0,res2=0;
if(ql <= mid) res1 += query(id*2,ql,qr);
if(qr > mid) res2 += query(id*2+1,ql,qr);
return (res1 + res2);
}

void solve()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n+1;i++){
scanf("%d",&a[i]);
}
build(1,1,n+1);
while(q--){
int a,b,c,w;
scanf("%d%d%d%d",&a,&b,&c,&w);
b++; c++;
if(a == 0) update(1,b,c,w,a);
else update(1,b,c,w,a);
printf("%d\n",query(1,1,n+1));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: