线段树区间修改之双标记 【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)); }}
阅读全文
0 0
- 线段树区间修改之双标记 【lazy两重标记并且分类讨论】
- 线段树区间修改 lazy标记 大法
- SKYLINE uva+线段树+区间的修改+lazy标记
- 线段树lazy标记
- 线段树模板(区间和+区间最大值 + LAZY标记)
- 区间修改区间查询 lazy标记
- hdu-4587-线段树的区间操作- lazy标记
- 线段树区间更新模板(lazy延迟标记)(1698)
- hdu 1698 线段树区间更新入门(lazy标记)
- 专题 线段树 E(区间更新,使用lazy标记)
- bzoj 1798 线段树 双lazy标记
- 线段树 -- 区间修改 【下放懒人标记】
- 线段树lazy标记??Hdu4902
- Transformation(线段树 + lazy 标记)
- 线段树lazy标记2
- hdu 3397 Sequence operation (线段树+区间合并+双Lazy标记)
- 线段树求区间最大值+区间更新+区间求和+lazy标记
- 线段树 (区间修改 区间查询 延迟标记)
- LG. 1003 铺地毯
- 高精度操作数值 BigDecimal类和BinInteger类
- Java多线程编程
- 利用Apache commons exec 实现指定应用打开对应文件
- uva 11461
- 线段树区间修改之双标记 【lazy两重标记并且分类讨论】
- 博客开篇随便
- Appium ios新的定位方式FindsByIosNSPredicate
- spring 或 springboot统一异常处理
- IE下预览pdf失败可能及解决方案
- hdu2962 限制最短路+枚举
- 机器学习笔记:kNN算法
- 图像处理基础
- php、mysql查询当天,查询本周,查询本月的数据实例(字段是时间戳)