我们将sumv[o] 定义成sumv[o] = sumv[o] * mult[o] + addv[o] * 区间长度,
这样就可以正常进行线段树的更新与查询啦。
这道题完全提升了我对线段树的认识。
#include<cstdio>
using namespace std;
const int maxn = 100000 + 3;
long long mod;
int val[maxn];
long long sumv[maxn << 2], mult[maxn<<2], addv[maxn<<2];
inline void push_down(int o,int l,int r)
{
int mid = (l + r) >> 1, ls = (o<<1), rs = (o<<1)|1;
if(mult[o] != 1)
{
sumv[ls] = (sumv[ls] * mult[o]) % mod, sumv[rs] = (sumv[rs] * mult[o]) % mod;
mult[ls] = (mult[ls] * mult[o]) % mod, mult[rs] = (mult[rs] * mult[o]) % mod;
addv[ls] = (addv[ls] * mult[o]) % mod, addv[rs] = (addv[rs] * mult[o]) % mod;
mult[o] = 1;
}
if(addv[o] != 0)
{
if(mid >= l)sumv[ls] = (sumv[ls] + addv[o] * (mid - l + 1)) % mod;
if(mid + 1 <= r)sumv[rs] = (sumv[rs] + addv[o] * (r - mid)) % mod;
addv[ls] += addv[o], addv[rs] += addv[o];
addv[o] = 0;
}
}
void build_Tree(int l,int r,int o)
{
if(l > r)return;
mult[o] = 1;
if(l == r)
{
sumv[o] = val[l] % mod; return;
}
int mid = (l + r) >> 1, ls = (o<<1), rs = (o<<1)|1;
build_Tree(l,mid,ls);
build_Tree(mid + 1,r,rs);
sumv[o] = (sumv[ls] + sumv[rs]) % mod;
}
void update_mult(int l,int r,int L,int R,int o,int k)
{
if(l > r || r < L || l > R)return;
if(l >= L && r <= R)
{
sumv[o] = (sumv[o] * k) % mod;
addv[o] *= k, mult[o] *= k;
addv[o] %= mod, mult[o] %= mod;
return;
}
push_down(o,l,r);
int mid = (l + r) >> 1, ls = (o<<1), rs = (o<<1)|1;
update_mult(l,mid,L,R,ls,k);
update_mult(mid + 1,r ,L, R,rs,k);
sumv[o] = (sumv[ls] + sumv[rs]) % mod;
}
void update_add(int l,int r,int L,int R,int o,int k)
{
if(l > r || r < L || l > R)return;
if(l >= L && r <= R)
{
sumv[o] = (sumv[o] + k * (r - l + 1)) % mod;
addv[o] += k;
return;
}
push_down(o,l,r);
int mid = (l + r) >> 1, ls = (o<<1), rs = (o<<1)|1;
update_add(l,mid,L,R,ls,k);
update_add(mid + 1,r ,L, R,rs,k);
sumv[o] = (sumv[ls] + sumv[rs]) % mod;
}
long long query(int l,int r,int L,int R,int o)
{
if(l > r || r < L || l > R)return 0;
if(l >= L && r <= R)return sumv[o];
push_down(o,l,r);
int mid = (l + r) >> 1, ls = (o<<1), rs = (o<<1)|1;
long long tmp = 0;
tmp += query(l,mid,L,R,ls);
tmp += query(mid + 1,r,L,R,rs);
tmp %= mod;
return tmp;
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m;
scanf("%d%d%lld",&n,&m,&mod);
for(int i = 1;i <= n;++i)scanf("%d",&val[i]);
build_Tree(1,n,1);
while(m--)
{
int x,y,k,opt;
scanf("%d%d%d",&opt,&x,&y);
if(opt <= 2)scanf("%d",&k);
if(opt == 1)update_mult(1,n,x,y,1,k);
if(opt == 2)update_add(1,n,x,y,1,k);
if(opt == 3)printf("%lld\n",query(1,n,x,y,1));
}
return 0;
}