线段树Lazy-tag
来源:互联网 发布:淘宝禁止出售的药品 编辑:程序博客网 时间:2024/05/29 18:22
由来
线段树求区间极值的时候,每次都需要修改包含在插入区间的所有节点,这样是不可能承受的!于是lazy思想也就是Lazy-tag是一个非常不错的优化。
实现
lazy思想的含义就是“要做的时候再做,不然不做”。这听起来不太可能,但实际上根据树的性质,这是可以实现的,只需要使用Lazy-tag:
对于一个节点,我们记录一个tag表示还没有传递下去的值(也就是操作时到这个节点停止了,后面没有遍历过),然后再写一个Pushdown来传递这个标记。
这里以动态统计问题为例:
void Pushdown(int id){ if (tr[id].L==tr[id].R) return; LL tag=tr[id].tag;tr[id].tag=0; tr[id*2].tag+=tag; tr[id*2].sum+=tag*(tr[id*2].R-tr[id*2].L+1); tr[id*2+1].tag+=tag; tr[id*2+1].sum+=tag*(tr[id*2+1].R-tr[id*2+1].L+1);}
模板(动态统计问题)
#include<cstdio>typedef long long LL;const int maxn=100005,maxm=100005;int n,m;struct zzk{ int L,R; LL now,sum; //now记录还没传下去的大小}tr[4*maxn];void Build(int id,int L,int R){ tr[id].L=L;tr[id].R=R; if (L==R) return; int mid=L+(R-L>>1); Build(id*2,L,mid);Build(id*2+1,mid+1,R);}void Pushdown(int id){ if (tr[id].L==tr[id].R) return; LL now=tr[id].now;tr[id].now=0; tr[id*2].now+=now; tr[id*2].sum+=now*(tr[id*2].R-tr[id*2].L+1); tr[id*2+1].now+=now; tr[id*2+1].sum+=now*(tr[id*2+1].R-tr[id*2+1].L+1);}void Insert(int id,int L,int R,LL x){ Pushdown(id); if (tr[id].L==L&&tr[id].R==R) { tr[id].now=x;tr[id].sum+=x*(tr[id].R-tr[id].L+1); return; } int mid=tr[id].L+(tr[id].R-tr[id].L>>1); if (R<=mid) Insert(id*2,L,R,x); else if (L>mid) Insert(id*2+1,L,R,x); else Insert(id*2,L,mid,x),Insert(id*2+1,mid+1,R,x); tr[id].sum=tr[id*2].sum+tr[id*2+1].sum; //更新一下答案}LL Ask(int id,int L,int R){ Pushdown(id); if (tr[id].L==tr[id].R) return tr[id].sum; int mid=tr[id].L+(tr[id].R-tr[id].L>>1); if (R<=mid) return Ask(id*2,L,R); else if (L>mid) return Ask(id*2+1,L,R); else return Ask(id*2,L,mid)+Ask(id*2+1,mid+1,R);}char getrch() {char ch=getchar();while (ch!='A'&&ch!='S') ch=getchar();return ch;}int main(){ int i,x,y,z; freopen("num.in","r",stdin); freopen("num.out","w",stdout); scanf("%d%d",&n,&m); Build(1,1,n); for (i=1;i<=m;i++) if (getrch()=='A') scanf("%d%d%d",&x,&y,&z),Insert(1,x,y,z); else scanf("%d%d",&x,&y),printf("%lld\n",Ask(1,x,y)); return 0;}
模板(区间极值问题)
#include<cstdio>#include<cstdlib>const int maxn=100005,MAXINT=((1<<30)-1)*2+1;int n,te;struct zzk{ int L,R,MAX,now; //MAX表示这个区间的最大值,now表示目前存放的还没传递下去的数}tr[4*maxn];int max2(int x,int y) {if (x>y) return x; else return y;}void Build(int id,int L,int R){ int mid=L+(R-L>>1); tr[id].L=L;tr[id].R=R;tr[id].MAX=-MAXINT;tr[id].now=-MAXINT; if (L<=mid&&mid+1<=R) Build(id*2,L,mid),Build(id*2+1,mid+1,R);}void Pushup(int id) //把值传递上来{ if (id==1) return; tr[id>>1].MAX=max2(tr[id].MAX,tr[id>>1].MAX);}void Pushdown(int id) //把now传递下去{ if (tr[id].L==tr[id].R) return; int now=tr[id].now;tr[id].now=-MAXINT; //now传递之后就没有了 tr[id*2].now=max2(tr[id*2].now,now); //把now传递下去之后儿子就得到了now,可以为儿子的儿子传递 tr[id*2].MAX=max2(tr[id*2].MAX,now); //同时修正一下MAX tr[id*2+1].now=max2(tr[id*2+1].now,now); tr[id*2+1].MAX=max2(tr[id*2+1].MAX,now);}void Insert(int id,int L,int R,int x){ Pushdown(id); //接下来可能要用到id的儿子了,传递一下 if (tr[id].L==L&&tr[id].R==R) { tr[id].now=x;tr[id].MAX=max2(x,tr[id].MAX); //因为下面不做了但是可能需要修正,于是记录now Pushup(id); //修正完毕,传递上去 return; } int mid=tr[id].L+(tr[id].R-tr[id].L>>1); if (R<=mid) Insert(id*2,L,R,x); else if (L>mid) Insert(id*2+1,L,R,x); else { Insert(id*2,L,mid,x); Insert(id*2+1,mid+1,R,x); } Pushup(id); //修正完毕,传递上去}int Ask(int id,int L,int R){ Pushdown(id); //可能要询问id的儿子,所以传递下去 if (tr[id].L==L&&tr[id].R==R) return tr[id].MAX; int mid=tr[id].L+(tr[id].R-tr[id].L>>1); if (R<=mid) return Ask(id*2,L,R); else if (L>mid) return Ask(id*2+1,L,R); else return max2(Ask(id*2,L,mid),Ask(id*2+1,mid+1,R));}int getrch() {char ch=getchar();while (ch!='A'&&ch!='S') ch=getchar();return ch;}int main(){ int i,x,y,z,now; char ch; freopen("max.in","r",stdin); freopen("max.out","w",stdout); scanf("%d%d",&n,&te); Build(1,1,n); while (te--) { ch=getrch(); if (ch=='A') scanf("%d%d%d",&x,&y,&z),Insert(1,x,y,z); else { scanf("%d%d",&x,&y);now=Ask(1,x,y); if (now==-MAXINT) printf("The teacher is silly!\n"); else printf("%d\n",now); } } return 0;}
1 0
- 线段树Lazy-tag
- 线段树及Lazy-Tag
- 线段树 lazy tag 小合集
- 线段树多lazy-tag(两个)
- POJ3468 线段树 + Lazy Tag (延迟标记)
- hdu 3911, 3397 线段树 lazy tag
- POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】
- AHOI2009维护序列--线段树lazy tag模板
- 线段树——区间修改(Lazy-Tag)
- [CodeVS 4927] 线段树练习5:两个Lazy Tag的线段树
- poj 2777 Count Color(线段树 Lazy-Tag思想 成段更新+区间统计)
- poj 1823 Hotel(线段树·区间更新·lazy tag)
- poj 3225 Help with Intervals 线段树lazy-tag求解区间运算
- [bzoj 3064] Tyvj 1518 CPU监控:线段树的Lazy tag
- HDU 1698Just a Hook(线段树 + Lazy Tag(延迟更新))
- POJ 3468A Simple Problem with Integers(线段树 + Lazy Tag(延迟更新))
- POJ 3667 Hotel(线段树的合并+lazy tag)【很详细!!】
- POJ 2777 Count Color (线段树的区间更新+lazy tag)
- Django基本命令与初始用法
- 【zzuli】九进制转化为十进制
- Hibernate 单向N-1关联
- linux 邮件服务器
- 朴素贝叶斯分类器——机器学习算法(二)
- 线段树Lazy-tag
- 【LeetCode】42. Trapping Rain Water
- wordnet的中文支持项目open multilingual wordnet分析试用
- 进程间通信,同步
- Java框架说明
- CNY Live Casino Cashback 0.75%+0.1% Damacai 4D
- 创建新文件 的问题
- 3.17学习内容---七彩鲜花销售系统
- jdbc接口核心的API