UESTC - 1597An easy problem C(线段树)

An easy problem C

Time Limit: 4000/2000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

N个数排成一列,有三种操作。1.给一段区间内的每个数乘上一个非负整数。2.给一段区间内的每个数加上一个非负整数.3.询问一段区间的和模上P的值。

Input

第一行两个整数N(1≤N≤100000)表示数的个数,P(1≤P≤1000000000)表示模的值。接下来一行N个整数ai(0≤ai≤1000000000),接下来一行一个整数M(1≤M≤100000)表示操作数量,接下来M行每行描述一个操作。第一种操作描述:1 L R C(0≤C≤1000000000),表示把L到R这段区间每个数乘上一个C。第二种操作描述:2 L R C(0≤C≤1000000000),表示把L到R这段区间每个数加上一个C。第三种操作3 L R 表示询问L到R这段区间内的数的和模上P的值。

Output

对面每个询问,输出对应的答案,每个询问占一行。

Sample input and output

Sample Input Sample Output
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
2
35
8

分清乘与加的先后关系,这题就简单多了;

对于一个区间,如果要乘,不止要原本的乘val,还要把要加的数也乘上val

                         如果要加,那就无所谓了

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=100005;
typedef long long ll;
ll t[N<<2],ladd[N<<2],lmul[N<<2],n,p,m;
void build(ll l,ll r,ll rt)
{
    lmul[rt]=1,ladd[rt]=0;
    if(l==r)
    {
        scanf("%lld",&t[rt]);
        return;
    }
    ll m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
     t[rt]=(t[rt<<1]+t[rt<<1|1])%p;
}
void pushdown(ll rt,ll num)
{
    ladd[rt<<1]=(ladd[rt<<1]*lmul[rt]+ladd[rt])%p;
    ladd[rt<<1|1]=(ladd[rt<<1|1]*lmul[rt]+ladd[rt])%p;
    lmul[rt<<1]=(lmul[rt<<1]*lmul[rt])%p;
    lmul[rt<<1|1]=(lmul[rt<<1|1]*lmul[rt])%p;
    t[rt<<1]=(t[rt<<1]*lmul[rt]+(num-num/2)*ladd[rt])%p;
    t[rt<<1|1]=(t[rt<<1|1]*lmul[rt]+(num/2)*ladd[rt])%p;
    ladd[rt]=0;
    lmul[rt]=1;
}
void updata(ll x,ll y,ll l,ll r,ll rt,ll val,ll op)
{
    if(x<=l&&r<=y)
    {
        if(op==1)
        {
            ladd[rt]=(ladd[rt]*val)%p;
            lmul[rt]=(lmul[rt]*val)%p;
            t[rt]=(t[rt]*val)%p;
        }
        else
        {
            ladd[rt]=(ladd[rt]+val);
            t[rt]=(t[rt]+(r-l+1)*val)%p;
        }
        return;
    }
    pushdown(rt,r-l+1);
    ll m=(l+r)>>1;
    if(x<=m)
        updata(x,y,l,m,rt<<1,val,op);
    if(y>m)
        updata(x,y,m+1,r,rt<<1|1,val,op);
    t[rt]=(t[rt<<1]+t[rt<<1|1])%p;
}
ll query(ll x,ll y,ll l,ll r,ll rt)
{
    if(x<=l&&y>=r)
       return t[rt]%p;
    pushdown(rt,r-l+1);
    ll m=(l+r)>>1;
    ll res=0;
    if(x<=m)
        res+=query(x,y,l,m,rt<<1);
     if(y>m)
      res+=query(x,y,m+1,r,rt<<1|1);
        return res%p;
}
int main()
{
    scanf("%lld%lld",&n,&p);
    build(1,n,1);
    scanf("%lld",&m);
    ll x,y,val,op;
    for(ll i=0;i<m;i++)
    {
        scanf("%lld",&op);
        if(op==1)
        {
            scanf("%lld%lld%lld",&x,&y,&val);
            updata(x,y,1,n,1,val,1);
        }
        else if(op==2)
        {
            scanf("%lld%lld%lld",&x,&y,&val);
            updata(x,y,1,n,1,val,2);
        }
        else
        {
            scanf("%lld%lld",&x,&y);
            printf("%lld\n",query(x,y,1,n,1));
        }
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值