bzoj 1798

来源:互联网 发布:vb.net实例 编辑:程序博客网 时间:2024/06/06 04:14

题意:给出一个数列,支持三个操作。1.一个区间内所有数加上x  2.一个区间内所有数乘上x 3.询问一个区间内所有数的和。


分析:不同于区间和,还要标记一个乘法。对于每一个线段树上的点,标记两个数组mul(乘),val(加)。

         (ax+b)*e+f=a*e*x+b*e+f

技能:

void pushdown(ll root,ll len)
{
    if ((mul[root]-1) || val[root])
    {
        mul[root<<1]=mul[root]*mul[root<<1]%p; //对于儿子的mul标记直接乘上当前的mul
        val[root<<1]=(val[root]+val[root<<1]*mul[root]%p)%p;
        sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p;//儿子的sum直接更新
        mul[root<<1|1]=mul[root]*mul[root<<1|1]%p;
        val[root<<1|1]=(val[root]+val[root<<1|1]*mul[root]%p)%p;
        sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p;
        mul[root]=1,val[root]=0;
    }
}


代码:

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define N 150010
#define rep(i,a,b) for (ll i=a;i<=b;++i)
 
ll mul[N<<2],sum[N<<2],val[N<<2],n,p,m;

ll read()
{
    ll f=1,x=0;char ch=getchar();
    for (;ch>'9'||ch<'0';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

void pushdown(ll root,ll len)
{
    if ((mul[root]-1) || val[root])
    {
        mul[root<<1]=mul[root]*mul[root<<1]%p;
        val[root<<1]=(val[root]+val[root<<1]*mul[root]%p)%p;
        sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p;
        mul[root<<1|1]=mul[root]*mul[root<<1|1]%p;
        val[root<<1|1]=(val[root]+val[root<<1|1]*mul[root]%p)%p;
        sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p;
        mul[root]=1,val[root]=0;
    }
}

void pushup(ll root)
{
    sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}

void add(ll root,ll l,ll r,ll L,ll R,ll y)
{
    if (L<=l&&r<=R)
    {
        (sum[root]+=(r-l+1)*y%p)%=p;
        (val[root]+=y)%=p;
        return;
    }
    pushdown(root,r-l+1);
    ll mid=l+r>>1;
    if (L<=mid) add(root<<1,l,mid,L,R,y);
    if (mid<R) add(root<<1|1,mid+1,r,L,R,y);
    pushup(root);
}

void Mul(ll root,ll l,ll r,ll L,ll R,ll y)
{
    if (L<=l&&r<=R)
    {
        (sum[root]*=y)%=p;
        (mul[root]*=y)%=p;
        (val[root]*=y)%=p;
        return;
    }
    pushdown(root,r-l+1);
    ll mid=l+r>>1;
    if (L<=mid) Mul(root<<1,l,mid,L,R,y);
    if (mid<R) Mul(root<<1|1,mid+1,r,L,R,y);
    pushup(root);
}

ll query(ll root,ll l,ll r,ll L,ll R)
{
    if (L<=l&&r<=R) return sum[root];
    pushdown(root,r-l+1);
    ll mid=l+r>>1,ans=0;
    if (L<=mid) (ans+=query(root<<1,l,mid,L,R))%=p;
    if (mid<R) (ans+=query(root<<1|1,mid+1,r,L,R))%=p;
    pushup(root);
    return ans;
}

int main()
{
    n=read(); p=read();
    rep(i,0,(N<<2)-1) mul[i]=1;
    rep(i,1,n)
    {
        ll x=read();
        add(1,1,n,i,i,x);
    }
    m=read();
    rep(i,1,m)
    {
        ll x=read();
        if (x==1)
        {
            ll u=read(),v=read(),c=read();
            Mul(1,1,n,u,v,c);
        }
        else if (x==2)
        {
            ll u=read(),v=read(),c=read();
            add(1,1,n,u,v,c);
        }
        else
        {
            ll u=read(),v=read();
            printf("%lld\n",query(1,1,n,u,v));
        }
    }
    return 0;
}
原创粉丝点击