老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 nnn 的数列,不妨设为 a1,a2,⋯ ,an。有如下三种操作形式:
- 把数列中的一段数全部乘一个值;
- 把数列中的一段数全部加一个值;
- 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PPP 的值。
输入格式
第一行两个整数 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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
样例
Input | 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 |
初始时数列为 {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。
数据范围与提示的要求就是数据很大,需要注意范围,要用树形结构。
思路:
树形结构。
每次结果都模一下,减小储存数据。
注意ax+b的乘法加法的优先级关系。
#include<iostream>
typedef long long ll;
using namespace std;
const int N=2e6;
int n,M;
ll P,a[N+5];
struct tree
{
int l,r;
ll sum,mu,ad;
}T[N*4+5];
void pushup(int k)
{
//printf("pushup");
T[k].sum =(T[k*2].sum +T[k*2+1].sum )%P;
}
void pushdown(int k)
{
//printf("pushdown");
int len=T[k].r -T[k].l +1;
T[k<<1].sum =(T[k<<1].sum *T[k].mu +T[k].ad *(len+1>>1))%P;
T[k<<1|1].sum =(T[k<<1|1].sum *T[k].mu +T[k].ad *(len>>1))%P;
T[k<<1].mu =T[k<<1].mu *T[k].mu %P;
T[k<<1|1].mu =T[k<<1|1].mu *T[k].mu %P;
T[k<<1].ad =(T[k<<1].ad *T[k].mu +T[k].ad )%P;
T[k<<1|1].ad =(T[k<<1|1].ad *T[k].mu +T[k].ad )%P;
T[k].mu =1,T[k].ad =0;
}
void build(int k,int l,int r)
{
T[k].mu =1,T[k].ad =0;
//printf("build");
T[k].l =l,T[k].r =r;
if(l==r)
{
T[k].sum =a[l];
T[k].sum %=P;
return;
}
int mid=(l+r)/2;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void mul(int k,int t,int g,ll c)
{
//printf("mul");
if(T[k].l >=t&&T[k].r <=g)
{
T[k].sum =T[k].sum *c%P;
T[k].mu =T[k].mu *c%P;
T[k].ad =T[k].ad *c%P;//foget
return;
}
pushdown(k);
int mid=(T[k].r +T[k].l )/2;
if(t<=mid)
mul(k<<1,t,g,c);
if(g>mid)
mul(k<<1|1,t,g,c);
pushup(k);
}
void add(int k,int t,int g,ll c)
{
//printf("add");
if(T[k].l >=t&&T[k].r <=g)
{
T[k].ad =(T[k].ad +c)%P;
T[k].sum =(T[k].sum +c*(T[k].r -T[k].l +1))%P;
return;
}
pushdown(k);
int mid=(T[k].r +T[k].l )/2;
if(t<=mid)
add(k<<1,t,g,c);
if(g>mid)
add(k<<1|1,t,g,c);
pushup(k);
}
ll query(int k,int t,int g)
{
//printf("query");
if(T[k].l>=t&&T[k].r <=g)
{
return T[k].sum ;
}
pushdown(k);
int mid=(T[k].l +T[k].r )/2;
ll s=0;
if(t<=mid)
s+=query(k<<1,t,g);
if(g>mid)
s+=query(k<<1|1,t,g);
s%=P;
return s;
}
int main()
{
scanf("%d %lld",&n,&P);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&M);
while(M--)
{
//for(int i=1;i<=n*4;i++)
// printf("%lld %lld %lld\n",T[i].sum ,T[i].mu ,T[i].ad );
int t=0,g=0,type=0;
ll c=0;
scanf("%d %d %d",&type,&t,&g);
if(type==1)
{
// printf("1");
scanf("%lld",&c);
mul(1,t,g,c);
}
else if(type==2)
{
// printf("2");
scanf("%lld",&c);
add(1,t,g,c);
}
else if(type==3)
{
// printf("3");
printf("%lld\n",query(1,t,g));
}
}
return 0;
}