BZOJ1798: [Ahoi2009]维护序列seq

BZOJ1798 [Ahoi2009]维护序列seq


题目描述

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。


输入

第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。


输出

对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。


Solution

深夜刷一刷水题
线段树模版,唯一要考虑的就是加和乘的优先级
可以当模版玩一玩

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAX 400000
#define LL long long
using namespace std;

LL sum[MAX],mul[MAX],add[MAX],mod;

void up_date(int cur)
{
    sum[cur]=(sum[cur<<1]+sum[cur<<1|1])%mod;
}

void creat(int L,int R,int x,int y,int cur)
{
    mul[cur]=1;
    add[cur]=0;
    sum[cur]+=y;
    if (L==R) return;
    int mid=(L+R)>>1;
    if (x>mid) creat(mid+1,R,x,y,cur<<1|1);
    else creat(L,mid,x,y,cur<<1);
    up_date(cur);
}

void push_down(int cur,int l,int r,int mid)
{
    if (mul[cur]==1 && add[cur]==0) return;
    mul[cur<<1]=mul[cur<<1]*mul[cur]%mod;
    add[cur<<1]=(add[cur<<1]*mul[cur]%mod+add[cur])%mod;
    sum[cur<<1]=(sum[cur<<1]*mul[cur]%mod+add[cur]*(LL)(mid-l+1)%mod)%mod;
    mul[cur<<1|1]=mul[cur<<1|1]*mul[cur]%mod;
    add[cur<<1|1]=(add[cur<<1|1]*mul[cur]%mod+add[cur])%mod;
    sum[cur<<1|1]=(sum[cur<<1|1]*mul[cur]%mod+add[cur]*(LL)(r-mid)%mod)%mod;
    mul[cur]=1;
    add[cur]=0;
    return;
}

void change_mul(int L,int R,int l,int r,int x,int cur)
{
    if (L>=l && R<=r)
    {
        mul[cur]=mul[cur]*(LL)x%mod;
        add[cur]=add[cur]*(LL)x%mod;
        sum[cur]=sum[cur]*(LL)x%mod;
        return;
    }
    int mid=(L+R)>>1;
    push_down(cur,L,R,mid);
    if (l<=mid) change_mul(L,mid,l,r,x,cur<<1);
    if (r>mid) change_mul(mid+1,R,l,r,x,cur<<1|1);
    up_date(cur);
}

void change_add(int L,int R,int l,int r,int x,int cur)
{
    if (L>=l && R<=r)
    {
        add[cur]=(add[cur]+(LL)x)%mod;
        sum[cur]=(sum[cur]+(LL)(R-L+1)*x%mod)%mod;
        return;
    }
    int mid=(L+R)>>1;
    push_down(cur,L,R,mid);
    if (l<=mid) change_add(L,mid,l,r,x,cur<<1);
    if (r>mid) change_add(mid+1,R,l,r,x,cur<<1|1);
    up_date(cur);
}

LL ask(int L,int R,int l,int r,int cur)
{
    if (L>=l && R<=r) return sum[cur];
    int mid=(L+R)>>1;
    LL ans=0;
    push_down(cur,L,R,mid);
    if (l<=mid) ans=(ans+ask(L,mid,l,r,cur<<1))%mod;
    if (r>mid) ans=(ans+ask(mid+1,R,l,r,cur<<1|1))%mod;
    up_date(cur);
    return ans;
}

int main()
{
//  freopen("bzoj1798.in","r",stdin);
    int n,m,a,b,c,i,x;
    scanf("%d%lld",&n,&mod);
    for (i=1;i<=n;i++) scanf("%d",&a),creat(1,n,i,a%mod,1);
    scanf("%d",&m);
    for (i=1;i<=m;i++)
    {
        scanf("%d",&x);
        if (x==1) scanf("%d%d%d",&a,&b,&c),change_mul(1,n,a,b,c%mod,1);
        if (x==2) scanf("%d%d%d",&a,&b,&c),change_add(1,n,a,b,c%mod,1);
        if (x==3) scanf("%d%d",&a,&b),printf("%lld\n",ask(1,n,a,b,1));
        for(int j=1;j<=n<<1;++j) printf("%lld ",add[j]);
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值