【Bzoj1798】维护序列seq

题意

线段树维护三个操作:区间加法,区间乘法,区间查询。

分析

需要打两个tag,注意先下放乘法之后再下放加法。

#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxx = 100000 + 50;
LL T[maxx<<2],Add[maxx<<2],mul[maxx<<2];
LL mod,z;
int n,m,pos,x,y;

template <class T> void P(T &a,const T &b) {a=(a+b)%mod;return;}
template <class T> void K(T &a,const T &b) {a=(a*b)%mod;return;}
template <class T> void F(T &a,const T &b,const T &c) {a=(a*b+c)%mod;return;}

namespace Y{

    void Build(int i,int l,int r){
        mul[i] = 1;Add[i] = 0;if(l == r) {scanf("%lld",&T[i]);return;}
        int mid = (l+r) >> 1;Build(i<<1,l,mid);Build(i<<1|1,mid+1,r);
        T[i] = (T[i<<1] + T[i<<1|1])%mod;
    }

    void pushdown(int i,int l,int r){
    	int mid = (l+r)>>1;
        K(mul[i<<1],mul[i]);K(mul[i<<1|1],mul[i]);
        F(Add[i<<1],mul[i],Add[i]);F(Add[i<<1|1],mul[i],Add[i]);
        F(T[i<<1],mul[i],(mid-l+1)*Add[i]);
        F(T[i<<1|1],mul[i],(r-mid)*Add[i]);
        mul[i] = 1;Add[i] = 0;
    }

    void modify(int i,int x,int y,int l,int r,LL k,int flag){
        if(x<=l && r<=y)
            if(flag == 1) {K(mul[i],k);K(Add[i],k);K(T[i],k);return;}
            else if(flag == 2) {P(Add[i],k);P(T[i],(LL)(r-l+1)*k);return;}
        if((mul[i]!=1) || (Add[i]!=0)) pushdown(i,l,r);int V=(l+r)>>1;
        if(x <= V) modify(i<<1,x,y,l,V,k,flag);
        if(y >  V) modify(i<<1|1,x,y,V+1,r,k,flag);
        T[i] = (T[i<<1] + T[i<<1|1])%mod;
    }
    
    LL Query(int i,int x,int y,int l,int r){
        LL Ans = 0;
        if(x<=l && r<=y) return T[i];int V=(l+r)>>1;
        if((mul[i]!=1) || (Add[i]!=0)) pushdown(i,l,r);
        if(x <= V) P(Ans,Query(i<<1,x,y,l,V));
        if(y >  V) P(Ans,Query(i<<1|1,x,y,V+1,r));
        return Ans;
    }

}
int main(){
    scanf("%d%lld",&n,&mod);Y :: Build(1,1,n);scanf("%d",&m);
    while( m-- ){
        scanf("%d%d%d",&pos,&x,&y);
        if(pos == 1||pos == 2) scanf("%lld",&z),Y :: modify(1,x,y,1,n,z,pos);
        if(pos == 3) printf("%lld\n",Y :: Query(1,x,y,1,n));
    }
    return 0;
}

模板的话还是短一点好嘛。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值