给定长度为 N N 的序列,执行以下有三种模 意义下的操作之一 M M 次:
1. 区间乘 ; 2.区间加 c c ;3.查询区间和。
直接线段树,维护两个标记,一个维护乘法,一个维护加法。但是区间乘一个数时,要把加法标记也乘上这个数。
#include <bits/stdc++.h>
int P, N, M, S[1 << 18], tag1[1 << 18], tag2[1 << 18], a[100010];
void Build(int u, int Ls, int Rs)
{
tag1[u] = 1;
if(Ls == Rs){ S[u] = a[Ls]; return ; }
int Mid = Ls + Rs >> 1;
Build(u << 1, Ls, Mid);
Build(u << 1 | 1, Mid + 1, Rs);
S[u] = (S[u << 1] + S[u << 1 | 1]) % P;
}
void Pd(int u, int Ls, int Rs)
{
int Mid = Ls + Rs >> 1;
if(tag1[u] != 1)
{
S[u << 1] = 1ll * S[u << 1] * tag1[u] % P;
tag1[u << 1] = 1ll * tag1[u << 1] * tag1[u] % P;
tag2[u << 1] = 1ll * tag2[u << 1] * tag1[u] % P;
S[u << 1 | 1] = 1ll * S[u << 1 | 1] * tag1[u] % P;
tag1[u << 1 | 1] = 1ll * tag1[u << 1 | 1] * tag1[u] % P;
tag2[u << 1 | 1] = 1ll * tag2[u << 1 | 1] * tag1[u] % P;
tag1[u] = 1;
}
if(tag2[u])
{
S[u << 1] = (S[u << 1] + 1ll * tag2[u] * (Mid - Ls + 1)) % P;
tag2[u << 1] = (tag2[u << 1] + tag2[u]) % P;
S[u << 1 | 1] = (S[u << 1 | 1] + 1ll * tag2[u] * (Rs - Mid)) % P;
tag2[u << 1 | 1] = (tag2[u << 1 | 1] + tag2[u]) % P;
tag2[u] = 0;
}
}
void MD1(int u, int Ls, int Rs, int l, int r, int c)
{
if(l <= Ls && Rs <= r)
{
S[u] = 1ll * S[u] * c % P;
tag1[u] = 1ll * tag1[u] * c % P;
tag2[u] = 1ll * tag2[u] * c % P;
return ;
}
Pd(u, Ls, Rs);
int Mid = Ls + Rs >> 1;
if(l <= Mid) MD1(u << 1, Ls, Mid, l, r, c);
if(r > Mid) MD1(u << 1 | 1, Mid + 1, Rs, l, r, c);
S[u] = (S[u << 1] + S[u << 1 | 1]) % P;
}
void MD2(int u, int Ls, int Rs, int l, int r, int c)
{
if(l <= Ls && Rs <= r)
{
S[u] = (S[u] + 1ll * (Rs - Ls + 1) * c) % P;
tag2[u] = (tag2[u] + c) % P;
return ;
}
Pd(u, Ls, Rs);
int Mid = Ls + Rs >> 1;
if(l <= Mid) MD2(u << 1, Ls, Mid, l, r, c);
if(r > Mid) MD2(u << 1 | 1, Mid + 1, Rs, l, r, c);
S[u] = (S[u << 1] + S[u << 1 | 1]) % P;
}
int QU(int u, int Ls, int Rs, int l, int r)
{
if(l <= Ls && Rs <= r) return S[u];
Pd(u, Ls, Rs);
int Mid = Ls + Rs >> 1, t1 = 0, t2 = 0;
if(l <= Mid) t1 = QU(u << 1, Ls, Mid, l, r);
if(r > Mid) t2 = QU(u << 1 | 1, Mid + 1, Rs, l, r);
S[u] = (S[u << 1] + S[u << 1 | 1]) % P;
return (t1 + t2) % P;
}
int main()
{
scanf("%d %d", &N, &P);
for(int i = 1; i <= N; ++i) scanf("%d", &a[i]);
Build(1, 1, N);
scanf("%d", &M);
for(int i = 1; i <= M; ++i)
{
int opt, l, r, c;
scanf("%d %d %d", &opt, &l, &r);
if(opt == 1)
{
scanf("%d", &c);
MD1(1, 1, N, l, r, c);
}
if(opt == 2)
{
scanf("%d", &c);
MD2(1, 1, N, l, r, c);
}
if(opt == 3) printf("%d\n", QU(1, 1, N, l, r));
}
return 0;
}