题目:luogu3373.
题目大意:给定一个长度为 n n n的序列,要求支持三种操作:
1.给某一段加一个数.
2.给某一段乘一个数.
3.查询某一段的和.
设操作数为 m m m, 1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105.
首先我们很容易用线段树维护没有区间乘法操作的情况,根据套路我们可以再给乘法搞个tag.
然后我们发现,加法tag和乘法tag撞在一起有点棘手…
其实这种情况很容易处理,我们直接钦定乘法会对加法标记产生影响,而加法不会对乘法标记产生影响即可.
也就是说每次打乘法标记的时候,顺便也给加法标记乘上乘法标记的贡献,加法标记照样打.
然后这道题就解决啦.时间复杂度 O ( n + m log n ) O(n+m\log n) O(n+mlogn).
那么AC代码如下:
#include
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
int n,m;
LL mod,a[N+9];
struct tree{
LL sum,add,mul;
int len;
}tr[N*4+9];
LL add(LL a,LL b){return a+b>=mod?a+b-mod:a+b;}
LL mul(LL a,LL b){return a*b%mod;}
void sadd(LL &a,LL b){a=add(a,b);}
void smul(LL &a,LL b){a=mul(a,b);}
void Pushup(int k){tr[k].sum=add(tr[k<<1].sum,tr[k<<1|1].sum);}
void Update_add(int k,LL v){sadd(tr[k].sum,mul(v,(LL)tr[k].len));sadd(tr[k].add,v);}
void Pushdown_add(int k){
if (!tr[k].add) return;
Update_add(k<<1,tr[k].add);Update_add(k<<1|1,tr[k].add);
tr[k].add=0;
}
void Update_mul(int k,LL v){smul(tr[k].sum,v);smul(tr[k].mul,v);smul(tr[k].add,v);}
void Pushdown_mul(int k){
if (tr[k].mul==1) return;
Update_mul(k<<1,tr[k].mul);Update_mul(k<<1|1,tr[k].mul);
tr[k].mul=1;
}
void Pushdown(int k){Pushdown_mul(k);Pushdown_add(k);}
void Build(int L,int R,int k){
tr[k].len=R-L+1;tr[k].mul=1;
if (L==R) {tr[k].sum=a[L]%mod;return;}
int mid=L+R>>1;
Build(L,mid,k<<1);Build(mid+1,R,k<<1|1);
Pushup(k);
}
void Change_add(int L,int R,LL v,int l,int r,int k){
if (L==l&&R==r) {Update_add(k,v);return;}
Pushdown(k);
int mid=l+r>>1;
if (R<=mid) Change_add(L,R,v,l,mid,k<<1);
else if (L>mid) Change_add(L,R,v,mid+1,r,k<<1|1);
else Change_add(L,mid,v,l,mid,k<<1),Change_add(mid+1,R,v,mid+1,r,k<<1|1);
Pushup(k);
}
void Change_mul(int L,int R,LL v,int l,int r,int k){
if (L==l&&R==r) {Update_mul(k,v);return;}
Pushdown(k);
int mid=l+r>>1;
if (R<=mid) Change_mul(L,R,v,l,mid,k<<1);
else if (L>mid) Change_mul(L,R,v,mid+1,r,k<<1|1);
else Change_mul(L,mid,v,l,mid,k<<1),Change_mul(mid+1,R,v,mid+1,r,k<<1|1);
Pushup(k);
}
LL Query_sum(int L,int R,int l,int r,int k){
if (L==l&&R==r) return tr[k].sum;
Pushdown(k);
int mid=l+r>>1;
if (R<=mid) return Query_sum(L,R,l,mid,k<<1);
else if (L>mid) return Query_sum(L,R,mid+1,r,k<<1|1);
else return add(Query_sum(L,mid,l,mid,k<<1),Query_sum(mid+1,R,mid+1,r,k<<1|1));
}
Abigail into(){
scanf("%d%d%lld",&n,&m,&mod);
for (int i=1;i<=n;++i)
scanf("%lld",&a[i]);
}
Abigail work(){
Build(1,n,1);
}
Abigail outo(){
int opt,l,r,x;
for (int i=1;i<=m;++i){
scanf("%d%d%d",&opt,&l,&r);
switch (opt){
case 1:
scanf("%d",&x);
Change_mul(l,r,(LL)x,1,n,1);
break;
case 2:
scanf("%d",&x);
Change_add(l,r,(LL)x,1,n,1);
break;
case 3:
printf("%lld\n",Query_sum(l,r,1,n,1));
break;
}
}
}
int main(){
into();
work();
outo();
return 0;
}