线段树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
原创粉丝点击