P3373 【模板】线段树 2 (未完待续)

P3373 【模板】线段树 2

强烈安利这个大佬 超赞!!!

 

题解

本来以为这个题拿着线段树1的板子改改就好了,但是发现事情并没有那么简单,改了两天。。。

我们看到这个题其实涉及啦乘法和加法两种运算,如何把这两种运算同时塞到懒标记当中呢??似乎有些困难

!!!那么我们可以开两个懒标记啊,一个记录乘法mul[ ],一个记录加法add[ ]

初始化

add[ ] 初始化当然为0,不加减任何数

mul[ ] 初始化当然为1 ,不乘任何数

标记下传以及ADD运算的时候两者都要维护

运算顺序

当我们乘法和加法的懒标记都有的时候

是先加后乘呢?

还是先乘后加呢?

ans:先乘后加

 

 

 

 

 

注意

这个题数据算着算着就很大了,一定要都开long long

还有一点就是忽略掉 if (add [ ] ==0)

 

代码

#include<bits/stdc++.h>

using namespace std;

#define ll long long    //一定要开long long ,不然会炸 
const int maxn=1e7+10;
ll n,m,x,y,v,opr,mod;
ll a[maxn],add[maxn*4],mul[maxn*4];
//add[]加法懒标记,mul[]乘法懒标记 
ll sum[maxn*4]; 
//前缀和 
ll ans;

void build(ll k,ll l,ll r)   //建树 
{
    mul[k]=1;  //初始化乘法前缀和为1,表示不变 
    if(l==r)
    {
        sum[k]=a[l];  return ;
    } 
    ll mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%mod;
}

void Add(ll k,ll l,ll r,ll mulp,ll sump)   //处理懒标记,先乘后加 
{
    sum[k]=(sum[k]*mulp+(r-l+1)*sump)%mod;
    add[k]=(add[k]*mulp+sump)%mod;
    mul[k]=(mul[k]*mulp)%mod;
}

void pushdown(ll k,ll l,ll r,ll mid)  //标记下传 
{
//    if(add[k]==0) return ;
    Add(k<<1,l,mid,mul[k],add[k]);
    Add(k<<1|1,mid+1,r,mul[k],add[k]);
    add[k]=0;   //清空懒标记 
    mul[k]=1;
}

void modifymul(ll k,ll l,ll r,ll x,ll y,ll v)  //乘法区间修改 
{
    if(x<=l&&r<=y) return Add(k,l,r,v,0);
    ll mid=(l+r)>>1;
    pushdown(k,l,r,mid);
    if(x<=mid) modifymul(k<<1,l,mid,x,y,v);
    if(mid<y) modifymul(k<<1|1,mid+1,r,x,y,v);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%mod;  //维护前缀和 
}

void modifysum(ll k,ll l,ll r,ll x,ll y,ll v)  //加法区间修改 
{
    if(x<=l&&r<=y) return Add(k,l,r,1,v);
    ll mid=(l+r)>>1;
    pushdown(k,l,r,mid);
    if(x<=mid) modifysum(k<<1,l,mid,x,y,v);
    if(mid<y) modifysum(k<<1|1,mid+1,r,x,y,v);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%mod;
}

long long query(ll k,ll l,ll r,ll x,ll y)  //区间询问 
{
    if(x<=l&&r<=y) return sum[k];
    ll mid=(l+r)>>1;
    ll res=0;
    pushdown(k,l,r,mid);
    if(x<=mid) res+=query(k<<1,l,mid,x,y);
    if(mid<y) res+=query(k<<1|1,mid+1,r,x,y);
    return res%mod;
}

int main()
{
    scanf("%ld%ld%ld",&n,&m,&mod);
    for(ll i=1;i<=n;i++)
      scanf("%ld",&a[i]);
    
    build(1,1,n);
    
    for(ll i=1;i<=m;i++)
    {
        scanf("%ld%ld%ld",&opr,&x,&y);
        if(opr==1)
        {
            scanf("%ld",&v);
            modifymul(1,1,n,x,y,v);
        }
        if(opr==2)
        {
            scanf("%ld",&v);
            modifysum(1,1,n,x,y,v);
        }
        if(opr==3)
        {
            ans=query(1,1,n,x,y);
            printf("%ld\n",ans%mod);
        }
    }
    
    return 0;
}

 

posted @ 2019-06-29 10:06  晔子  阅读(231)  评论(0编辑  收藏  举报