非常好的线段树,使我的板子旋转(
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, m, w[N], mod;
struct Node { int l, r, sum; } tr[N << 2];
struct Tag { int mul,add; } tag[N << 2];
Node pushup(Node a, Node b)
{
return {a.l, b.r, (a.sum + b.sum) % mod};
}
int len(Node a) { return a.r - a.l + 1; }
Node BrushAndTag(int u, Tag v)
{
tr[u].sum = ((LL)tr[u].sum * v.mul % mod + (LL)v.add * len(tr[u])) % mod;
tag[u].mul = ((LL) tag[u].mul * v.mul) % mod;
tag[u].add = ((LL)tag[u].add * v.mul + v.add) % mod;
return tr[u];
}
void pushdown(int u)
{
BrushAndTag(u << 1, tag[u]);
BrushAndTag(u << 1 | 1, tag[u]);
tag[u] = {1, 0};
}
Node build(int u, int l, int r)
{
tag[u] = {1, 0};
if (l == r) return tr[u] = {l, r, w[r] % mod};
int mid = (l + r) >> 1;
return tr[u] = pushup(build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r));
}
Node modify(int u, int l, int r, Tag v)
{
if (tr[u].r < l || tr[u].l > r) return tr[u];
if (tr[u].l >= l && tr[u].r <= r) return tr[u] = BrushAndTag(u, v);
pushdown(u);
return tr[u] = pushup(modify(u << 1, l, r, v), modify(u << 1 | 1, l, r, v));
}
Node query(int u, int l, int r)
{
if (!tr[u].l) return tr[0];
if (tr[u].r < l || tr[u].l > r) return tr[0];
if (tr[u].l >= l && tr[u].r <= r) return tr[u];
pushdown(u);
return pushup(query(u << 1, l, r), query(u << 1 | 1, l, r));
}
int main()
{
scanf("%d%d", &n, &mod);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
build(1, 1, n);
scanf("%d", &m);
while (m -- )
{
int t, a, b, c;
scanf("%d%d%d", &t, &a, &b);
if (t == 1)
{
scanf("%d", &c);
modify(1, a, b, {c, 0});
}
else if (t == 2)
{
scanf("%d", &c);
modify(1, a, b, {1, c});
}
else printf("%d\n", query(1, a, b).sum);
}
return 0;
}