【题目】
题目描述:
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
样例数据:
输入
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。
【数据范围】
数据编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
N | 10 | 1000 | 1000 | 10000 | 60000 | 70000 | 80000 | 90000 | 100000 | 100000 |
M | 10 | 1000 | 1000 | 10000 | 60000 | 70000 | 80000 | 90000 | 100000 | 100000 |
【分析】
emmm,线段树模板题,这里就不多赘述,不清楚的可以自己百度
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,p;
int a[N],sum[4*N];
int add[4*N],mul[4*N];
void Build(int root,int l,int r)
{
add[root]=0;
mul[root]=1;
if(l==r)
{
sum[root]=a[l];
return;
}
int mid=(l+r)>>1;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
void Pushdown_mul(int root,int l,int r)
{
mul[root<<1]=(1ll*mul[root<<1]*mul[root])%p;
mul[root<<1|1]=(1ll*mul[root<<1|1]*mul[root])%p;
add[root<<1]=(1ll*add[root<<1]*mul[root])%p;
add[root<<1|1]=(1ll*add[root<<1|1]*mul[root])%p;
sum[root<<1]=(1ll*sum[root<<1]*mul[root])%p;
sum[root<<1|1]=(1ll*sum[root<<1|1]*mul[root])%p;
mul[root]=1;
}
void Pushdown_add(int root,int l,int r)
{
int mid=(l+r)>>1;
add[root<<1]=(add[root<<1]+add[root])%p;
add[root<<1|1]=(add[root<<1|1]+add[root])%p;
sum[root<<1]=(sum[root<<1]+1ll*(mid-l+1)*add[root]%p)%p;
sum[root<<1|1]=(sum[root<<1|1]+1ll*(r-mid)*add[root]%p)%p;
add[root]=0;
}
void Multiply(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
add[root]=(1ll*add[root]*k)%p;
mul[root]=(1ll*mul[root]*k)%p;
sum[root]=(1ll*sum[root]*k)%p;
return;
}
int mid=(l+r)>>1;
if(mul[root]!=1) Pushdown_mul(root,l,r);
if(add[root]!=0) Pushdown_add(root,l,r);
if(x<=mid) Multiply(root<<1,l,mid,x,y,k);
if(y>mid) Multiply(root<<1|1,mid+1,r,x,y,k);
sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
void Add(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
add[root]=(add[root]+k)%p;
sum[root]=(sum[root]+1ll*(r-l+1)*k%p)%p;
return;
}
int mid=(l+r)>>1;
if(mul[root]!=1) Pushdown_mul(root,l,r);
if(add[root]!=0) Pushdown_add(root,l,r);
if(x<=mid) Add(root<<1,l,mid,x,y,k);
if(y>mid) Add(root<<1|1,mid+1,r,x,y,k);
sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
int Query(int root,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
return sum[root];
int ans=0,mid=(l+r)>>1;
if(mul[root]!=1) Pushdown_mul(root,l,r);
if(add[root]!=0) Pushdown_add(root,l,r);
if(x<=mid) ans=(ans+Query(root<<1,l,mid,x,y))%p;
if(y>mid) ans=(ans+Query(root<<1|1,mid+1,r,x,y))%p;
return ans;
}
int main()
{
int x,y,i,s,k;
scanf("%d%d",&n,&p);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
Build(1,1,n);
scanf("%d",&m);
for(i=1;i<=m;++i)
{
scanf("%d",&s);
if(s==1)
{
scanf("%d%d%d",&x,&y,&k);
Multiply(1,1,n,x,y,k);
}
if(s==2)
{
scanf("%d%d%d",&x,&y,&k);
Add(1,1,n,x,y,k);
}
if(s==3)
{
scanf("%d%d",&x,&y);
printf("%d\n",Query(1,1,n,x,y));
}
}
return 0;
}