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

来源:互联网 发布:01年总决赛科比数据 编辑:程序博客网 时间:2024/05/19 12:13

//前面说了单标记的, 那如果都有了? 这个时候就要用双标记了, 并且讨论下之前标记的情况.

板子题
模板 :

/** @Cain*/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));    }}
原创粉丝点击