线段树——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\n",ans);
}
}
return 0;
}
举个例子:1-5,+5,*3,如果先乘,就错了