线段树——I

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。

有长为 nn 的数列,不妨设为 a1,a2,⋯,ana1,a2,⋯,an。有如下三种操作形式:

  • 把数列中的一段数全部乘一个值;
  • 把数列中的一段数全部加一个值;
  • 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。

Input

第一行两个整数 nn 和 PP;

第二行含有 nn 个非负整数,从左到右依次为 a1,a2,⋯,ana1,a2,⋯,an;

第三行有一个整数 MM,表示操作总数;

从第四行开始每行描述一个操作,输入的操作有以下三种形式:

  • 操作 11:"1 t g c",表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai×cai×c;
  • 操作 22:"2 t g c",表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai+cai+c;
  • 操作 33:"3 t g",询问所有满足 t≤i≤gt≤i≤g 的 aiai 的和模 PP 的值。

同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

Output

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

Example

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

Output

2
35
8

Note

对于全部测试数据,1≤t≤g≤n,0≤c,ai≤109,1≤P≤1091≤t≤g≤n,0≤c,ai≤109,1≤P≤109。

样例说明:

初始时数列为 {1,2,3,4,5,6,7}{1,2,3,4,5,6,7};

经过第 11 次操作后,数列为 {1,10,15,20,25,6,7}{1,10,15,20,25,6,7};

对第 22 次操作,和为 10+15+20=4510+15+20=45,模 4343 的结果是 22;

经过第 33 次操作后,数列为 {1,10,24,29,34,15,16}{1,10,24,29,34,15,16};

对第 44 次操作,和为 1+10+24=351+10+24=35,模 4343 的结果是 3535;

对第 55 次操作,和为 29+34+15+16=9429+34+15+16=94,模 4343 的结果是 88。

memset置换-1,0,inf,意外其他数据会出现bug。学到了

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
#define N 410000
ll sum[N];
ll a[N];
ll lazy[N],lazy1[N];
ll  n,p;
void build(ll l,ll r,ll rt){//每一步都要mod
    if(l==r){
        sum[rt]=a[l]%p;
        return;
    }
    ll mid=(l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
    sum[rt]=(sum[rt*2]+sum[rt*2+1])%p;
}
void pushdown(ll l,ll r,ll rt){//先更新乘,再更新加
    if(lazy1[rt]!=1){
        sum[rt*2]*=lazy1[rt];
        sum[rt*2]=sum[rt*2]%p;
        sum[rt*2+1]*=lazy1[rt];
        sum[rt*2+1]=sum[rt*2+1]%p;
        lazy1[rt*2]*=lazy1[rt];
        lazy1[rt*2]=lazy1[rt*2]%p;
        lazy1[rt*2+1]*=lazy1[rt];
        lazy1[rt*2+1]=lazy1[rt*2+1]%p;
        lazy[2*rt]*=lazy1[rt];
        lazy[2*rt+1]*=lazy1[rt];
        lazy[2*rt]=lazy[2*rt]%p;
        lazy[2*rt+1]=lazy[2*rt+1]%p;
        lazy1[rt]=1;
    }
    if(lazy[rt]){
        sum[rt*2]+=l*lazy[rt];
        sum[rt*2]=sum[rt*2]%p;
        sum[rt*2+1]+=r*lazy[rt];
        sum[rt*2+1]=sum[rt*2+1]%p;
        lazy[rt*2]+=lazy[rt];
        lazy[rt*2]=lazy[rt*2]%p;
        lazy[rt*2+1]+=lazy[rt];
        lazy[rt*2+1]=lazy[rt*2+1]%p;
        lazy[rt]=0;
    }
}
void updatej(ll l1,ll r1,ll v,ll l,ll r,ll rt){//每一步都要pushdown
    if(l1<=l&&r1>=r){
        sum[rt]=sum[rt]+v*(r-l+1);
        sum[rt]=sum[rt]%p;
        lazy[rt]+=v;
        lazy[rt]=lazy[rt]%p;
        return;
    }
    ll mid=(l+r)/2;
    pushdown(mid-l+1,r-mid,rt);
    if(l1<=mid){
        updatej(l1,r1,v,l,mid,rt*2);
    }
    if(r1>mid){
        updatej(l1,r1,v,mid+1,r,rt*2+1);
    }
    sum[rt]=(sum[rt*2]+sum[rt*2+1])%p;
}
void updatem(ll l1,ll r1,ll v,ll l,ll r,ll rt){
    if(l1<=l&&r1>=r){
        sum[rt]*=v;
        sum[rt]=sum[rt]%p;
        lazy1[rt]*=v;
        lazy1[rt]=lazy1[rt]%p;
        lazy[rt]*=v;
        lazy[rt]=lazy[rt]%p;
        return;
    }
    ll mid=(l+r)/2;
    pushdown(mid-l+1,r-mid,rt);
    if(l1<=mid){
        updatem(l1,r1,v,l,mid,rt*2);
    }
    if(r1>mid){
        updatem(l1,r1,v,mid+1,r,rt*2+1);
    }
    sum[rt]=(sum[rt*2]+sum[rt*2+1])%p;
}
ll query(ll l1,ll r1,ll l,ll r,ll rt){
    if(l1<=l&&r1>=r){
        return sum[rt];
    }
    ll mid=(l+r)/2;
    ll ret=0;
    pushdown(mid-l+1,r-mid,rt);
    if(l1<=mid){
      ret+=query(l1,r1,l,mid,rt*2);
      ret=ret%p;
    }
    if(r1>mid){
        ret+=query(l1,r1,mid+1,r,rt*2+1);
    }
    return ret%p;
}
int main()
{
    for(ll i=1;i<=N;i++){
        lazy1[i]=1;
    }
    memset(lazy,0,sizeof(lazy));
    scanf("%lld %lld",&n,&p);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    build(1,n,1);
    ll m;
    scanf("%lld",&m);
    while(m--){
        ll a,b,c,d;
        scanf("%lld",&a);
        if(a==1){
            scanf("%lld %lld %lld",&b,&c,&d);
            updatem(b,c,d,1,n,1);
        }
        if(a==2){
            scanf("%lld %lld %lld",&b,&c,&d);
            updatej(b,c,d,1,n,1);
        }
        if(a==3){
            scanf("%lld %lld",&b,&c);
            ll ans=query(b,c,1,n,1);
            printf("%lld
",ans);
        }
    }
    return 0;
}

举个例子:1-5,+5,*3,如果先乘,就错了

原文地址:https://www.cnblogs.com/skyleafcoder/p/12319550.html