AHoi 行星序列

Description

“神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决了一些模拟飞行中发现的问题,今天指导老师交给他一个任务,在这次模拟飞行的路线上有N个行星,暂且称它们为一个行星序列,并将他们从1至n标号,在宇宙未知力量的作用下这N个行星的质量是不断变化的,所以他们对飞船产生的引力也会不断变化,小可可的任务就是在飞行途中计算这个行星序列中某段行星的质量和,以便能及时修正飞船的飞行线路,最终到达目的地,行星序列质量变化有两种形式:
1,行星序列中某一段行星的质量全部乘以一个值
2,行星序列中某一段行星的质量全部加上一个值
由于行星的质量和很大,所以求出某段行星的质量和后只要输出这个值模P的结果即可,小可可被这个任务难住了,聪明的你能够帮他完成这个任务吗?

Input

第一行两个整数N和P(1<=p<=1000000000);

第二行含有N个非负整数,从左到右依次为a1,a2,…………,an(0<=ai<。100000000,1<=i<=n),其中ai表示第i个行星的质量:

第三行有一个整数m,表示模拟行星质量变化以及求质量和等操作的总次数。从第四行开始每行描述一个操作,输入的操作有以下三种形式:
操作1:1 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai*c
操作2:2 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai+c
操作3:3 t g 表示输出所有满足t<=i<=g的ai的和模p的值
其中:1<=t<=g<=N,0<=c<=10000000

注:同一行相邻的两数之间用一个空格隔开,每行开头和末尾没有多余空格
输出:对每个操作3,按照它在输入中出现的顺序,依次一行输出一个整数表示所求行星质量和

Sample Input

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

Sample Output

2
35
8

Key To Problem

本题显然是一道线段树问题,与裸线段树相比它需要两种修改,也就是双标记
因为乘法的优先级大于加法,所以遇到乘法就直接乘,加法就先加后乘

CODE

#include <cstdio>
#include <algorithm>
#define N 100010
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1
typedef long long ll;
using namespace std;
int n,m,mod;
ll f[N<<2];
ll mix[N<<2];
ll add[N<<2];

void PushUp(int rt)
{
    f[rt]=(f[ls]+f[rs])%mod;
}

void PushDown_add(int rt,ll c)
{
    if(add[rt])
    {
        add[ls]=(add[ls]+add[rt])%mod;
        add[rs]=(add[rs]+add[rt])%mod;
        f[ls]=(f[ls]+(add[rt]*(c-(c>>1)))%mod)%mod;
        f[rt<<1|1]=(f[rt<<1|1]+(add[rt]*(c>>1))%mod)%mod;
        add[rt]=0;
    }
}

void PushDown_mix(int rt)
{
    if(mix[rt]!=1)
    {
        mix[ls]=mix[ls]*mix[rt]%mod;
        mix[rs]=mix[rs]*mix[rt]%mod;
        add[ls]=add[ls]*mix[rt]%mod;
        add[rs]=add[rs]*mix[rt]%mod;
        f[ls]=f[ls]*mix[rt]%mod;
        f[rs]=f[rs]*mix[rt]%mod;
        mix[rt]=1;
    }
}

void build(int l,int r,int rt)
{
    add[rt]=0,mix[rt]=1;
    if(l==r)
    {
        scanf("%d",&f[rt]);
        f[rt]%=mod;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}

void update(int u,int L,int R,ll c,int l,int r,int rt)
{
    if(l>=L && r<=R)
    {
        if(u==1)
        {
            mix[rt]=mix[rt]*c%mod;
            add[rt]=add[rt]*c%mod;
            f[rt]=f[rt]*c%mod;
        }else
        {
            add[rt]=(add[rt]+c)%mod;
            f[rt]=(f[rt]+c*(r-l+1))%mod;
        }
        return ;
    }
    PushDown_mix(rt);
    PushDown_add(rt,(ll)r-l+1);
    int mid=(l+r)>>1;
    if(mid>=L)
        update(u,L,R,c,lson);
    if(mid<R)
        update(u,L,R,c,rson);
    PushUp(rt);
}

ll query(int L,int R,int l,int r,int rt)
{
    if(l>=L && r<=R)
        return f[rt];
    PushDown_mix(rt);
    PushDown_add(rt,(ll)r-l+1);
    int mid=(l+r)>>1;
    ll ans=0;
    if(mid>=L)
        ans=(ans+query(L,R,lson))%mod;
    if(mid<R)
        ans=(ans+query(L,R,rson))%mod;
    return ans;
}

int main()
{
//  freopen("seq.in","r",stdin);
//  freopen("seq.out","w",stdout);
    scanf("%d%d",&n,&mod);
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int a,x,y;
        ll z;
        scanf("%d%d%d",&a,&x,&y);
        if(a==1||a==2)
        {
            scanf("%I64d",&z);
            update(a,x,y,z%mod,1,n,1);
        }else
        {
            printf("%I64d\n",query(x,y,1,n,1));
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值