题意:
给你一个数组,有5种操作,如下:
- 操作 1: 格式:1 l l l r r r k k k ;含义:将区间 [ l , r ] [l,r] [l,r] 内每个英雄的攻击力加上 k k k
- 操作 2: 格式:2 l l l r r r k k k ; 含义:将区间 [ l , r ] [l,r] [l,r] 内每个英雄的攻击力乘上 k k k
- 操作 3: 格式:3 l l l r r r k k k ;含义:将区间 [ l , r ] [l,r] [l,r] 内每个英雄的攻击力置为 k k k
- 操作4:格式:4 x x x ;含义:在最后一个英雄后增加一个攻击力为 x x x 的英雄
- 操作5: 格式:5 l l l r r r k k k ;含义:输出区间 [ l , r ] [l,r] [l,r] 内每个英雄的攻击力的和并对 p p p取模
思路:
单独的1操作,单独的2操作就是线段树基本操作,主要是1,2操作混合起来有点难,怎么打懒标记?我们设置一个add代表加法的懒标记,mul代表乘法的懒标记。
先考虑对某个节点加懒标记:
- 为这个节点加add标记,直接加即可;加乘法标记,如果之间这个节点有add标记,那么之前的add标记也要乘以这个值,因为 ( a + b ) ∗ v a l = a ∗ v a l + b ∗ v a l (a+b)*val = a*val + b*val (a+b)∗val=a∗val+b∗val;
再考虑如何下传:
- 因为节点下传标记之前,节点的值已经更新了,就考虑下传问题,首先add来说,下传后的左右儿子的add应该等于: a d d [ s o n ] ∗ m u l [ f a t h e r ] + a d d [ f a t h e r ] add[son]*mul[father] + add[father] add[son]∗mul[father]+add[father];
- 对于mul来说,下传就直接乘就可以了。
感觉三言两语讲不清,还是结合代码看看吧。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5+100;
ll tr[maxn * 4],add[maxn * 4],mul[maxn * 4],mod;
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define ls o<<1
#define rs o<<1|1
#define mid (l+r)/2
void pushup(int o)
{
tr[o] = (tr[ls] + tr[rs])%mod;
}
void down(int o,int l,int r)
{
if(mul[o] == 1 && add[o] == 0)return ;
tr[ls] = (tr[ls]*mul[o]%mod + add[o]*(ll)(mid-l+1)%mod) % mod;
tr[rs] = (tr[rs]*mul[o]%mod + add[o]*(ll)(r-mid)%mod) % mod;
add[ls] = (add[ls]*mul[o]%mod + add[o])%mod;
add[rs] = (add[rs]*mul[o]%mod + add[o])%mod;
mul[ls] = (mul[ls]*mul[o])%mod;
mul[rs] = (mul[rs]*mul[o])%mod;
mul[o] = 1,add[o] = 0;
}
void up(int o,int l,int r,int p,ll val)
{
if(l == r)
{
tr[o] = val%mod;
return ;
}
down(o,l,r);
if(p <= mid)up(lson,p,val);
else up(rson,p,val);
pushup(o);
}
void up_add(int o,int l,int r,int L,int R,int val)
{
if(l >= L && r <= R)
{
tr[o] = (tr[o] + 1ll*(r-l+1)*val%mod) % mod;
add[o] = (add[o] + val)%mod;
return ;
}
down(o,l,r);
if(L <= mid)up_add(lson,L,R,val);
if(R > mid)up_add(rson,L,R,val);
pushup(o);
}
void up_mul(int o,int l,int r,int L,int R,int val)
{
if(l >= L && r <= R)
{
tr[o] = (tr[o]*(ll)val)%mod;
add[o] = (add[o]*(ll)val)%mod;
mul[o] = (mul[o]*(ll)val)%mod;
return ;
}
down(o,l,r);
if(L <= mid)up_mul(lson,L,R,val);
if(R > mid)up_mul(rson,L,R,val);
pushup(o);
}
ll qu(int o,int l,int r,int L,int R)
{
if(l >= L && r <= R)return tr[o]%mod;
down(o,l,r);
ll ans = 0;
if(L <= mid)ans = (ans + qu(lson,L,R)%mod) % mod;
if(R > mid)ans = (ans + qu(rson,L,R)%mod) % mod;
return ans;
}
int main()
{
int n,m,N;
ll x;
scanf("%d%d%d",&n,&m,&mod);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
up(1,1,n+m+5,i,x);
}
N = n;
n = n + m + 5;
int op,l,r,k;
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
if(op == 1)
{
scanf("%d%d%d",&l,&r,&k);
up_add(1,1,n,l,r,k);
}
else if(op == 2)
{
scanf("%d%d%d",&l,&r,&k);
up_mul(1,1,n,l,r,k);
}
else if(op == 3)
{
scanf("%d%d%d",&l,&r,&k);
up_mul(1,1,n,l,r,0);
up_add(1,1,n,l,r,k);
}
else if(op == 4)
{
scanf("%d",&k);
up(1,1,n,++N,k);
}
else if(op == 5)
{
scanf("%d%d",&l,&r);
printf("%lld\n",qu(1,1,n,l,r)%mod);
}
}
return 0;
}