NotOnlySuccess大神的飘逸版线段树

吐槽:在模板题,我的丑陋的线段树跑了984ms,而大神的只跑了364ms,看来我的代码还是太丑了QAQ


大神的线段树也没什么大优化,就是不知道为什么超级快,或许是我以前看的线段树代码不好吧。。。
我推荐这个线段树的主要原因就是非常好写,空间也是非常小,思路极其清晰。
好了,废话不多说,直接上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100001;
ll sum[maxn<<2];
ll add[maxn<<2];
inline void pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
    if(l==r){
        scanf("%lld",&sum[rt]);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
inline void pushdown(int rt,int len){
    if(add[rt]){
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(len-(len>>1));
        sum[rt<<1|1]+=add[rt]*(len>>1);
        add[rt]=0;
    }
}
void update(int L,int R,int c,int l,int r,int rt){
    if(L<=l&&r<=R){
        add[rt]+=c;
        sum[rt]+=c*(r-l+1);
        return;
    }
    pushdown(rt,r-l+1);
    int mid=(l+r)>>1;
    if(L<=mid)update(L,R,c,l,mid,rt<<1);
    if(mid+1<=R)update(L,R,c,mid+1,r,rt<<1|1);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        return sum[rt];
    }
    pushdown(rt,r-l+1);
    ll ans=0;
    int mid=(l+r)>>1;
    if(L<=mid)ans+=query(L,R,l,mid,rt<<1);
    if(mid+1<=R)ans+=query(L,R,mid+1,r,rt<<1|1);
    return ans;
}
int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        int g;
        scanf("%d",&g);
        if(g&1){
            int l,r;
            ll c;
            scanf("%d %d %lld",&l,&r,&c);
            update(l,r,c,1,n,1);
        }
        else{
            int l,r;
            scanf("%d %d",&l,&r);
            printf("%lld\n",query(l,r,1,n,1));
        }
    }
    return 0;
}

以上是区间加+区间和
下面是区间加+区间乘+区间和:(这代码好难调啊)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100001;
ll p;
ll sum[maxn<<2];
ll add[maxn<<2];
ll mul[maxn<<2];
inline void pushup(int rt){
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
}
inline void mark(int l,int r,int rt,ll a,ll b){
    sum[rt]=(sum[rt]*a+(r-l+1)*b)%p;
    mul[rt]=(mul[rt]*a)%p;
    add[rt]=(add[rt]*a+b)%p;
}
inline void pushdown(int l,int r,int rt){
    if(mul[rt]!=1||add[rt]!=0){
        int mid=(l+r)>>1;
        mark(l,mid,rt<<1,mul[rt],add[rt]);
        mark(mid+1,r,rt<<1|1,mul[rt],add[rt]);
        add[rt]=0;
        mul[rt]=1;
    }
}
void build(int l,int r,int rt){
    mul[rt]=1;
    if(l==r){
        scanf("%lld",&sum[rt]);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void update(int L,int R,int l,int r,int rt,ll a,ll b){
    if(L<=l&&r<=R){
        mark(l,r,rt,a,b);
        return;
    }
    pushdown(l,r,rt);
    int mid=(l+r)>>1;
    if(L<=mid)update(L,R,l,mid,rt<<1,a,b);
    if(mid+1<=R)update(L,R,mid+1,r,rt<<1|1,a,b);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        return sum[rt]%p;
    }
    pushdown(l,r,rt);
    ll ans=0;
    int mid=(l+r)>>1;
    if(L<=mid)ans+=query(L,R,l,mid,rt<<1);
    if(mid+1<=R)ans+=query(L,R,mid+1,r,rt<<1|1);
    return ans%p;
}
int main(){
    int n,m;
    scanf("%d %d %lld",&n,&m,&p);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        int g;
        scanf("%d",&g);
        if(g==1){
            int l,r;
            ll c;
            scanf("%d %d %lld",&l,&r,&c);
            update(l,r,1,n,1,c,0);
        }
        else if(g==2){
            int l,r;
            ll c;
            scanf("%d %d %lld",&l,&r,&c);
            update(l,r,1,n,1,1,c);
        }
        else{
            int l,r;
            scanf("%d %d",&l,&r);
            printf("%lld\n",query(l,r,1,n,1));
        }
    }
    return 0;
}

end

posted @ 2017-08-25 20:53  玫葵之蝶  阅读(181)  评论(0编辑  收藏  举报