线段树lazy标记永久化

来源:互联网 发布:老师与学生网络交流图 编辑:程序博客网 时间:2024/06/05 03:42

更新:之前写错了,是(fr-fl+1)*u,已改正

例题:codevs 1082(好吧就是改段求段) bzoj 3110(树套树,但可以练手)

1、为什么要有这玩意:当我们用可持久化的数据结构lasy标志可能不能下传,或者用动态开点线段树时如果标记下传会造成无用空间。

2、实现:

以下内容纯属自己YY。

最主要思路,标记不下传,查询时经过一个节点就加上lazy值。

修改函数:大致上跟普通线段树差不多,但是因为标记不下传了,儿子不能得到lazy中的信息,所以维护时要加上自己lazy值

tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c+(r-l+1)*tr[x].u;

查询函数:这个有较大更改,首先我多传了个值u,表示当前lazy值有多少。

对于没有访问过的点,自然直接返回u*区间长度就可以了。

然后在返回值的时候也有把u值加上,访问儿子时加上自己的lazy。

LL findans(int x,int l,int r,int fl,int fr,LL u){    if(!x) return u*(LL)(fr-fl+1);    if(l==fl&&fr==r) return tr[x].c+(LL)(r-l+1)*u;    int mid=(l+r)/2;    if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr,u+tr[x].u);    if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr,u+tr[x].u);    return findans(tr[x].lc,l,mid,fl,mid,u+tr[x].u)+findans(tr[x].rc,mid+1,r,mid+1,fr,u+tr[x].u);}

因为是蒟蒻瞎想的,口胡如有错误,欢迎指出。

code:(codevs 1082)

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#define LL long longusing namespace std;struct node{    int lc,rc;LL c,u;}tr[400010];int trlen=0;int n,m,root=0;void update(int &x,int l,int r,int fl,int fr,LL c){    if(!x) x=++trlen;    if(l==fl&&r==fr){tr[x].u+=c;tr[x].c+=c*(r-l+1);return;}    int mid=(l+r)/2;    if(fr<=mid) update(tr[x].lc,l,mid,fl,fr,c);    else if(fl>mid) update(tr[x].rc,mid+1,r,fl,fr,c);    else update(tr[x].lc,l,mid,fl,mid,c),update(tr[x].rc,mid+1,r,mid+1,fr,c);    tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c+(r-l+1)*tr[x].u;}LL findans(int x,int l,int r,int fl,int fr,LL u){    if(!x) return u*(LL)(fr-fl+1);    if(l==fl&&fr==r) return tr[x].c+(LL)(r-l+1)*u;    int mid=(l+r)/2;    if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr,u+tr[x].u);    if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr,u+tr[x].u);    return findans(tr[x].lc,l,mid,fl,mid,u+tr[x].u)+findans(tr[x].rc,mid+1,r,mid+1,fr,u+tr[x].u);}int main(){scanf("%d",&n);for(int i=1;i<=n;i++){int x;scanf("%d",&x);update(root,1,n,i,i,(LL)x);}scanf("%d",&m);for(int i=1;i<=m;i++){int tmp,l,r,x;scanf("%d %d %d",&tmp,&l,&r);if(tmp==1) scanf("%d",&x),update(root,1,n,l,r,(LL)x);else printf("%lld\n",findans(root,1,n,l,r,0LL));}}


原创粉丝点击