老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 N 的数列,不妨设为 a1,a2,…,aN。
有如下三种操作形式:
把数列中的一段数全部乘一个值;
把数列中的一段数全部加一个值;
询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 P 的值。
输入格式
第一行两个整数 N 和 P;
第二行含有 N 个非负整数,从左到右依次为 a1,a2,…,aN;
第三行有一个整数 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 的值。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出格式
对每个操作 3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
数据范围
1≤N,M≤105,
1≤t≤g≤N,
0≤c,ai≤109,
1≤P≤109
输入样例:
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
样例解释
初始时数列为 {1,2,3,4,5,6,7};
经过第 1 次操作后,数列为 {1,10,15,20,25,6,7};
对第 2 次操作,和为 10+15+20=45,模 43 的结果是 2;
经过第 3 次操作后,数列为 {1,10,24,29,34,15,16};
对第 4 次操作,和为 1+10+24=35,模 43 的结果是 35;
对第 5 次操作,和为 29+34+15+16=94,模 43 的结果是 8。
//区间乘加操作,我们要按照优先级运算。要先乘后加。乘和加可以看成一个操作
(a*c)+d 如果是乘 让d=0即可
如果是加 让c=1即可
对于乘操作,懒惰标记直接乘
对于加操作,懒惰标记先乘后加。
线段树维护总和,乘法懒惰标记,加法懒惰标记
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10000;
typedef long long ll;
int a[N];
struct Node
{
int l,r;
int sum,add,mul;
}tr[N];
int n,m,p;
void eveal(Node &t,int add,int mul)
{
t.sum=((ll)t.sum*mul+(ll)(t.r-t.l+1)*add)%p;
t.mul=((ll)t.mul*mul)%p;
t.add=((ll)t.add*mul+add)%p;
}
void push_up(int u)
{
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void push_down(int u)
{
eveal(tr[u<<1],tr[u].add,tr[u].mul);
eveal(tr[u<<1|1],tr[u].add,tr[u].mul);
tr[u].add=0;tr[u].mul=1;
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,l,a[l],0,1};
return ;
}
tr[u]={l,r,0,0,1};
int mid=l+r>>1;
build(u<<1,l,mid);build(u<<1|1,mid+1,r);
push_up(u);
}
void update(int u,int l,int r,int add,int mul)
{
if(l<=tr[u].l&&r>=tr[u].r)
{
eveal(tr[u],add,mul);
return ;
}
push_down(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) update(u<<1,l,r,add,mul);
if(r>mid) update(u<<1|1,l,r,add,mul);
push_up(u);
}
int query(int u,int l,int r)
{
if(l<=tr[u].l&&r>=tr[u].r)
{
return tr[u].sum;
}
push_down(u);
int mid=tr[u].l+tr[u].r>>1;
int res=0;
if(l<=mid) res=query(u<<1,l,r);
if(r>mid) res=(res+query(u<<1|1,l,r))%p;
return res;
}
int main()
{
scanf("%d %d",&n,&p);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
int t,l,r,d;
scanf("%d %d %d",&t,&l,&r);
if(t==1)
{
scanf("%d",&d);
update(1,l,r,0,d);
}
else if(t==2)
{
scanf("%d",&d);
update(1,l,r,d,1);
}
else printf("%d\n",query(1,l,r)) ;
}
}