洛谷——P3373 【模板】线段树 2&& B 数据结构

P3373 【模板】线段树 2

 

题目描述

如题,已知一个数列,你需要进行下面三种操作:

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和

 

线段树维护区间乘法

1.如何修改?

  一个数去乘区间里的每一个数,那么这个区间的和会乘以这个数,需要乘法标记,初始化为1,乘法标记要乘以这个数,来下传到他的子树中,即更新他的子区间,当然,他的加法标记也要乘以这个数。

2.如何更新?

他子树的值=它的乘法标记*它子树的值+他子树的区间长度*它的加法标记

乘法标记更新,加法标记更新

某位大佬的线段树

#include<bits/stdc++.h>
#define N 4000000
#define LL long long
#define RE register
#define IN inline 

using namespace std;

IN void in(LL &x){
    RE char c=getchar();x=0;int f=1;
    while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    x*=f;
}

/*
1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和
*/

LL n,m,X,ans,p;
struct node{
    LL l,r,w,f,mul;
}e[N];

IN void build(LL k,LL l,LL r){
    e[k].l=l;e[k].r=r;e[k].mul=1;e[k].f=0;
    if(l==r){
        in(e[k].w);return;
    }LL mid=(l+r)/2;
    build(k*2,l,mid);build(k*2+1,mid+1,r);
    e[k].w=(e[k*2].w+e[k*2+1].w)%p;
}

IN void down(LL k){
    LL mu=e[k].mul,ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2;
    e[k*2].w=(e[k*2].w*mu+e[k].f*(mid-ll+1))%p;
    e[k*2+1].w=(e[k*2+1].w*mu+e[k].f*(rr-mid))%p;
    
    e[k*2].mul=(e[k*2].mul*mu)%p;
    e[k*2+1].mul=(e[k*2+1].mul*mu)%p;
    
    e[k*2].f=(e[k*2].f*mu+e[k].f)%p;
    e[k*2+1].f=(e[k*2+1].f*mu+e[k].f)%p;
    
    e[k].f=0;e[k].mul=1;
}

IN void mull(LL k,LL l,LL r){
    LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2;
    if(ll>=l&&rr<=r){
        e[k].w=(e[k].w*X)%p;
        e[k].mul=(e[k].mul*X)%p;
        e[k].f=(e[k].f*X)%p;
        return ;
    }if(e[k].f!=0||e[k].mul!=1) down(k);
    if(l<=mid) mull(k*2,l,r);if(r>mid) mull(k*2+1,l,r);
    e[k].w=(e[k*2].w+e[k*2+1].w)%p;
}

IN void change_LLerval(LL k,LL l,LL r){
    LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2;
    if(ll>=l&&rr<=r){
        e[k].f=(e[k].f+X)%p;
        e[k].w=((rr-ll+1)*X+e[k].w)%p;return ;
    }if(e[k].f!=0||e[k].mul!=1) down(k);
    if(l<=mid) change_LLerval(k*2,l,r);if(r>mid) change_LLerval(k*2+1,l,r);
    e[k].w=(e[k*2].w+e[k*2+1].w)%p;
}

IN void ask_LLerval(LL k,LL l,LL r){
    LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2;
    if(ll>=l&&rr<=r){
        ans=(e[k].w+ans)%p;return;
    }if(e[k].f!=0||e[k].mul!=1) down(k);
    if(l<=mid) ask_LLerval(k*2,l,r);if(r>mid) ask_LLerval(k*2+1,l,r);
    e[k].w=(e[k*2].w+e[k*2+1].w)%p;
}

int main()
{
    in(n);in(m);in(p);
    build(1,1,n);
    while(m--){
        LL tp,x,y,k;
        in(tp);in(x);in(y);
        if(tp!=3) in(k);
        if(tp==1) X=k,mull(1,x,y);
        else if(tp==2) X=k,change_LLerval(1,x,y);
        else{
            ans=0,ask_LLerval(1,x,y);
            printf("%d\n",ans);
        }
    }return 0;
}

 

 

B数据结构

 

链接:https://www.nowcoder.com/acm/contest/200/B
来源:牛客网

qn姐姐最好了~
qn姐姐给你了一个长度为n的序列还有m次操作让你玩,
1 l r 询问区间[l,r]内的元素和
2 l r 询问区间[l,r]内的元素的平方 和
3 l r x 将区间[l,r]内的每一个元素都乘上x
4 l r x 将区间[l,r]内的每一个元素都加上x

维护区间平方和的值。其他类似吧。。

 
#include<bits/stdc++.h>

#define N int(1e6)
#define LL long long

using namespace std;

void in(LL &x) {
    register char c=getchar();
    x=0;
    int f=1;
    while(!isdigit(c)) {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    x*=f;
}

struct node{
    LL l,r,w1,w2,mul,ad;
}tr[N];

inline void push_up(int k){
    tr[k].w1=tr[k<<1].w1+tr[k<<1|1].w1;
    tr[k].w2=tr[k<<1].w2+tr[k<<1|1].w2;
}

inline void build(LL k,LL l,LL r){
    tr[k].l=l,tr[k].r=r,tr[k].mul=1;
    if(l==r) {
        in(tr[k].w1);
        tr[k].w2=tr[k].w1*tr[k].w1;
        return;
    }
    LL mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push_up(k);
}

inline void push_down(LL k){
    tr[k<<1].w2=tr[k<<1].w2*tr[k].mul*tr[k].mul+tr[k<<1].w1*2*tr[k].ad+(tr[k<<1].r-tr[k<<1].l+1)*tr[k].ad*tr[k].ad;
    tr[k<<1].w1=tr[k<<1].w1*tr[k].mul+tr[k].ad*(tr[k<<1].r-tr[k<<1].l+1);
    tr[k<<1].ad+=tr[k].ad;
    tr[k<<1].mul*=tr[k].mul;
    
    tr[k<<1|1].w2=tr[k<<1|1].w2*tr[k].mul*tr[k].mul+tr[k<<1|1].w1*2*tr[k].ad+(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].ad*tr[k].ad;
    tr[k<<1|1].w1=tr[k<<1|1].w1*tr[k].mul+tr[k].ad*(tr[k<<1|1].r-tr[k<<1|1].l+1);
    tr[k<<1|1].ad+=tr[k].ad;
    tr[k<<1|1].mul*=tr[k].mul;
    
    tr[k].ad=0,tr[k].mul=1;
}

inline void update_mul(LL k,LL L,LL R,LL w){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R){
        tr[k].mul*=w;
        tr[k].ad*=w;
        tr[k].w2=w*w*tr[k].w2;
        tr[k].w1=w*tr[k].w1;
        return;
    }
    push_down(k);
    if(L<=mid) update_mul(k<<1,L,R,w);
    if(R>mid) update_mul(k<<1|1,L,R,w);
    push_up(k);
}

inline void update(LL k,LL L,LL R,LL w){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R){
        tr[k].w2+=tr[k].w1*2*w+(r-l+1)*w*w;
        tr[k].w1+=w*(r-l+1);
        tr[k].ad+=w;
        return;
    }
    push_down(k);
    if(L<=mid) update(k<<1,L,R,w);
    if(R>mid) update(k<<1|1,L,R,w);
    push_up(k);
}

LL query1(LL k,LL L,LL R){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R) return tr[k].w1;
    push_down(k);
    LL an=0; 
    if(L<=mid) an+=query1(k<<1,L,R);
    if(R>mid) an+=query1(k<<1|1,L,R);
    push_up(k);
    return an;
}

LL query2(LL k,LL L,LL R){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R) return tr[k].w2;
    push_down(k);
    LL an=0;
    if(L<=mid) an+=query2(k<<1,L,R);
    if(R>mid) an+=query2(k<<1|1,L,R);
    push_up(k);
    return an;
}

LL n,m;

int main()
{
    in(n),in(m);
    build(1,1,n);
    for(LL opt,l,r,w,i=1;i<=m;i++){
        in(opt),in(l),in(r);
        if(opt==1){
            printf("%lld\n",query1(1,l,r));
        }
        if(opt==2){
            printf("%lld\n",query2(1,l,r));
        }
        if(opt==3){
            in(w);
            update_mul(1,l,r,w);
        }
        if(opt==4){
            in(w);
            update(1,l,r,w);
        }
    }
    return 0;
}

 

posted @ 2018-10-05 22:29  清风我已逝  阅读(239)  评论(1编辑  收藏  举报