线段树区间修改之双标记 【lazy两重标记并且分类讨论】
2017-07-26 18:19
579 查看
//前面说了单标记的, 那如果都有了? 这个时候就要用双标记了, 并且讨论下之前标记的情况.
板子题
模板 :
//注意下标从0开始的.
解释版:
板子题
模板 :
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)); } }
相关文章推荐
- 线段树区间修改 lazy标记 大法
- 线段树区间更新模板(lazy延迟标记)(1698)
- 【题】【线段树(不用lazy的区间修改)】NKOJ 2997 狗 【nodgd造水题】
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 I.Minimum(线段树区间极值+分类讨论)
- hiho一下 第二十周(线段树区间修改+延迟标记)
- POJ3468 A Simple Problem with Integers(线段树区间更新,lazy标记)
- kb-07线段树-03--区间修改查询--lazy思想
- 线段树 (区间修改 区间查询 延迟标记)
- 【codevs1690】开关灯 线段树 区间修改+区间求和(标记)
- hdu 1698 线段树区间更新入门(lazy标记)
- hdoj 1698 Just a Hook 【线段树 区间修改】【线段树 + lazy思想】
- bzoj 1798 双标记区间修改线段树
- hihocoder1078线段树修改区间查询区间(懒标记)
- HDU 1698-Just a Hook(线段树_区间更新+lazy标记)
- FZU 2171 防守阵地 II(线段树区间更新【lazy标记】)
- 专题 线段树 E(区间更新,使用lazy标记)
- 线段树 -- 区间修改 【下放懒人标记】
- 洛谷-P3373 线段树 2(线段树,区间更新,lazy标记,好题)
- [模板] - 线段树 - Lazy标记 - 单点/区间更新 - 模板
- 线段树求区间最大值+区间更新+区间求和+lazy标记