线段树

区间加&区间求和

P3372【模板】线段树1

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 400010
#define ll long long
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

ll n,m,s[maxn],num,x,y,k;
ll t[maxn],tag[maxn];

void pushup(ll x){
    t[x]=t[x<<1]+t[x<<1|1];//=t[2*x]+t[2*x+1] 
}

void build(ll x,ll l,ll r){
    if(l==r){
        t[x]=s[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}

void tag_(ll x,ll len,ll k){
    t[x]+=len*k;
    tag[x]+=k;
}

void pushdown(ll x,ll l,ll r){
    if(tag[x]){
        ll mid=(l+r)>>1;
        tag_(x<<1,mid-l+1,tag[x]);
        tag_(x<<1|1,r-mid,tag[x]);
        tag[x]=0;
    }
}

void change(ll x,ll l,ll r,ll cl,ll cr,ll k){
    pushdown(x,l,r);
    if(cl<=l&&r<=cr) return tag_(x,r-l+1,k);
    ll mid=(l+r)>>1;
    if(cl<=mid) change(x<<1,l,mid,cl,cr,k);
    if(cr>=mid+1) change(x<<1|1,mid+1,r,cl,cr,k);
    pushup(x);
}

ll query(ll x,ll l,ll r,ll ql,ll qr){
    pushdown(x,l,r);
    if(ql<=l&&r<=qr) return t[x];
    ll mid=(l+r)>>1;
    ll ret=0;
    if(ql<=mid) ret+=query(x<<1,l,mid,ql,qr);
    if(qr>=mid+1) ret+=query(x<<1|1,mid+1,r,ql,qr);
    return ret;
}

int main(){
    read(n),read(m);
    for(int i=1;i<=n;i++) read(s[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        cin>>num;
        if(num==1) {
            cin>>x>>y>>k;
            change(1,1,n,x,y,k);
        }
        if(num==2) {
            cin>>x>>y;
            cout<<query(1,1,n,x,y)<<endl;
        }
    }
    return 0;
}

 70分 ↑

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 800010
#define ll long long
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

ll n,m,s[maxn],num,x,y,k;
ll t[maxn],tag[maxn]; 

void pushup(ll x){
    t[x]=t[x<<1]+t[x<<1|1];//=t[2*x]+t[2*x+1] 
}

void build(ll x,ll l,ll r){
    if(l==r){
        t[x]=s[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}

void tag_(ll x,ll len,ll k){
    t[x]+=len*k;
    tag[x]+=k;
}

void pushdown(ll x,ll l,ll r){
    if(tag[x]){
        ll mid=(l+r)>>1;
        tag_(x<<1,mid-l+1,tag[x]);
        tag_(x<<1|1,r-mid,tag[x]);
        tag[x]=0;
    }
}

void change(ll x,ll l,ll r,ll cl,ll cr,ll k){
    pushdown(x,l,r);
    if(cl<=l&&r<=cr) {tag_(x,r-l+1,k); return ;}
    ll mid=(l+r)>>1;
    if(cl<=mid) change(x<<1,l,mid,cl,cr,k);
    if(cr>=mid+1) change(x<<1|1,mid+1,r,cl,cr,k);
    pushup(x);
}

ll query(ll x,ll l,ll r,ll ql,ll qr){
    pushdown(x,l,r);
    if(ql<=l&&r<=qr) return t[x];
    ll mid=(l+r)>>1;
    ll ret=0;
    if(ql<=mid) ret+=query(x<<1,l,mid,ql,qr);
    if(qr>=mid+1) ret+=query(x<<1|1,mid+1,r,ql,qr);
    return ret;
}

int main(){
    read(n),read(m);
    for(int i=1;i<=n;i++) read(s[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        cin>>num;
        if(num==1) {
            cin>>x>>y>>k;
            change(1,1,n,x,y,k);
        }
        if(num==2) {
            cin>>x>>y;
            cout<<query(1,1,n,x,y)<<endl;
        }
    }
    return 0;
}

AC ↑

我也不知道为啥4倍空间过不了要开8倍才能过

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 400010
#define ll long long
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

ll n,m,s[maxn],num,x,y,k;
ll t[maxn],tag[maxn]; 

void pushup(ll x){
    t[x]=t[x<<1]+t[x<<1|1];//=t[2*x]+t[2*x+1] 
}

void build(ll x,ll l,ll r){
    if(l==r){
        t[x]=s[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}

void tag_(ll x,ll len,ll k){
    t[x]+=len*k;
    tag[x]+=k;
}

void pushdown(ll x,ll l,ll r){
    if(tag[x]){
        ll mid=(l+r)>>1;
        tag_(x<<1,mid-l+1,tag[x]);
        tag_(x<<1|1,r-mid,tag[x]);
        tag[x]=0;
    }
}

void change(ll x,ll l,ll r,ll cl,ll cr,ll k){
    if(cl<=l&&r<=cr) {tag_(x,r-l+1,k); return ;}
    pushdown(x,l,r);
    ll mid=(l+r)>>1;
    if(cl<=mid) change(x<<1,l,mid,cl,cr,k);
    if(cr>=mid+1) change(x<<1|1,mid+1,r,cl,cr,k);
    pushup(x);
}

ll query(ll x,ll l,ll r,ll ql,ll qr){
    if(ql<=l&&r<=qr) return t[x];
    pushdown(x,l,r);
    ll mid=(l+r)>>1;
    ll ret=0;
    if(ql<=mid) ret+=query(x<<1,l,mid,ql,qr);
    if(qr>=mid+1) ret+=query(x<<1|1,mid+1,r,ql,qr);
    return ret;
}

int main(){
    read(n),read(m);
    for(int i=1;i<=n;i++) read(s[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        cin>>num;
        if(num==1) {
            cin>>x>>y>>k;
            change(1,1,n,x,y,k);
        }
        if(num==2) {
            cin>>x>>y;
            cout<<query(1,1,n,x,y)<<endl;
        }
    }
    return 0;
}

AC ↑

好了我知道了,千万注意pushdown要放在return后面,这样4倍空间就能过了~

区间乘&区间加&区间求和

P3373【模板】线段树2

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 400010
#define ll long long
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

ll n,m,p,s[maxn],num,x,y,k;
ll t[maxn],tag1[maxn],tag2[maxn];//tag1->mul tag2->sum

void pushup(ll x){
    (t[x]=t[2*x]+t[2*x+1])%=p;
}

void build(ll x,ll l,ll r){
    tag1[x]=1,tag2[x]=0;
    if(l==r){
        t[x]=s[l];
        return ;
    }
    ll mid=(l+r)/2;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
    pushup(x);
}

void pushdown(ll x,ll l,ll r){
    ll mid=(l+r)/2;
    t[x*2]=(t[x*2]*tag1[x]%p+(mid-l+1)*tag2[x])%p;
    t[x*2+1]=(t[x*2+1]*tag1[x]%p+(r-mid)*tag2[x])%p;
    tag1[x*2]=tag1[x*2]*tag1[x]%p;
    tag1[x*2+1]=tag1[x*2+1]*tag1[x]%p;
    tag2[x*2]=(tag2[x*2]*tag1[x]+tag2[x])%p;
    tag2[x*2+1]=(tag2[x*2+1]*tag1[x]+tag2[x])%p;
    tag1[x]=1,tag2[x]=0;
}

/*
一定要先乘后加( 没人愿意乘法逆元先加后乘吧......
(a+b)*c=a*c+b*c;
a*c+b=a*c+b; 
*/
void mul(ll x,ll l ,ll r,ll cl,ll cr,ll k){
    if(cl<=l&&r<=cr){
        (t[x]*=k)%=p;
        (tag1[x]*=k)%=p;
        (tag2[x]*=k)%=p;
        return ;
    }
    pushdown(x,l,r);
    ll mid=(l+r)/2;
    if(cl<=mid) mul(x*2,l,mid,cl,cr,k);
    if(cr>=mid+1) mul(x*2+1,mid+1,r,cl,cr,k);
    pushup(x);
}

void sum(ll x,ll l ,ll r,ll cl,ll cr,ll k){
    if(cl<=l&&r<=cr){
        (t[x]+=(r-l+1)*k%p)%=p;
        (tag2[x]+=k)%=p;
        return ;
    }
    pushdown(x,l,r);
    ll mid=(l+r)/2;
    if(cl<=mid) sum(x*2,l,mid,cl,cr,k);
    if(cr>=mid+1) sum(x*2+1,mid+1,r,cl,cr,k);
    pushup(x);
}

ll query(ll x,ll l,ll r,ll ql,ll qr){
    if(ql<=l&&r<=qr) return t[x];
    pushdown(x,l,r);
    ll mid=(l+r)/2,ret=0;
    if(ql<=mid) (ret+=query(x*2,l,mid,ql,qr))%=p;
    if(qr>=mid+1) (ret+=query(x*2+1,mid+1,r,ql,qr))%=p;
    return ret;
}

int main(){
    read(n),read(m),read(p);
    for(int i=1;i<=n;i++) read(s[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        read(num);read(x),read(y);
        if(num==1){
            read(k);
            mul(1,1,n,x,y,k);
        }
        if(num==2){
            read(k);
            sum(1,1,n,x,y,k);
        }
        if(num==3){
            cout<<query(1,1,n,x,y)%p<<endl;
        }
    }
    return 0;
} 

 

posted @ 2021-02-16 18:05  DReamLion  阅读(33)  评论(0编辑  收藏  举报