ACWING1277. 维护序列
维护序列
描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 N 的数列,不妨设为 \(a_1,a_2,…,a_N\)。
有如下三种操作形式:
1、把数列中的一段数全部乘一个值;
2、把数列中的一段数全部加一个值;
3、询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 P 的值。
思路
需要记录的信息,\(L,R,add,mul\)。
先加再乘很难维护信息,故先乘再加。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int n,p,m;
typedef long long ll;
int w[N];
struct Node{
int l,r;
ll sum,add,mul;
}tr[N*4];
void pushup(int u){
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void eval(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 pushdown(int u){
eval(tr[u<<1],tr[u].add,tr[u].mul);
eval(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,r,w[r],0,1};
else{
tr[u]={l,r,0,0,1};
int mid=(l+r)>>1;
build(u<<1,l,mid); build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int l,int r,int add,int mul){
if(tr[u].l>=l && tr[u].r<=r) eval(tr[u],add,mul);
else{
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
if(l<=mid) modify(u<<1,l,r,add,mul);
if(r> mid) modify(u<<1|1,l,r,add,mul);
pushup(u);
}
}
ll query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r<=r) return tr[u].sum;
pushdown(u);
ll sum=0;
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) sum=query(u<<1,l,r)%p;
if(r>mid) sum=(sum+query(u<<1|1,l,r))%p;
return sum;
}
int main(){
cin>>n>>p;
for(int i=1;i<=n;i++) cin>>w[i];
build(1,1,n);
cin>>m;
while(m--){
int t,l,r,d;
scanf("%d%d%d",&t,&l,&r);
if(t==1){
scanf("%d",&d);
modify(1,l,r,0,d);
}
else if(t==2){
scanf("%d",&d);
modify(1,l,r,d,1);
}
else{
printf("%d\n",query(1,l,r));
}
}
return 0;
}