本题作为模板题实在是太屈才了, 是一道很好的题目,做完以后本人对线段树有了更深的理解。单就此题而言,两种修改操作是互相影响的,修改乘法的时候是要先考虑加法的修改。为了避免这种先加后乘的影响,我们在打 lazy-tag的时候要注意
lson.add = (t[o].add + lson.add * t[o].p) % mod;
即乘法之前先把加法的 lazy_tag 先乘出来,然后再更新加法的lazy_tag,
直接上码 (我知道你们只看这个) :
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define _rep(i, a, b) for(ll i = (a); i <=(b); ++i)
#define _rev(i, a, b) for(ll i = (a); i >=(b); --i)
#define _for(i, a, b) for(ll i = (a); i<(b); ++i)
#define _rof(i, a, b) for(ll i = (a); i>(b); --i)
#define maxn 100009
#define maxm 109
#define ll long long
#define met(a,b) memset((a),(b), sizeof(a))
#define db double
#define eps 1e-8
#define lowbit(x) x & (-x)
using namespace std;
ll mod;
struct node
{
ll l, r, p = 1;
ll add, sum;
#define le o << 1
#define ri o << 1 | 1
#define lson t[le]
#define rson t[ri]
}t[maxn * 4];
int n, m;
void spread(int o) {
assert(o <= maxn * 4);
if (t[o].l == t[o].r) {
t[o].p = 1;
t[o].add = 0;
return;
}
if (t[o].add || t[o].p != 1) {
lson.sum = (lson.sum * t[o].p + t[o].add * (lson.r - lson.l + 1)) % mod;
rson.sum = (rson.sum * t[o].p + t[o].add * (rson.r - rson.l + 1)) % mod;
lson.add = (t[o].add + lson.add * t[o].p) % mod;
rson.add = (t[o].add + rson.add * t[o].p) % mod;
lson.p = (lson.p * t[o].p) % mod;
rson.p = (rson.p * t[o].p) % mod;
t[o].p = 1;
t[o].add = 0;
}
}
void update(int o) {
assert(o <= maxn * 4);
t[o].sum = (lson.sum + rson.sum) % mod;
}
void build(int o, int l, int r) {
assert(o <= maxn * 4);
t[o].l = l, t[o].r = r;
if (l == r) { assert(scanf("%lld", &t[o].sum) == 1); return; }
int mid = l + r >> 1;
build(le, l, mid);
build(ri, mid + 1, r);
update(o);
}
void change(int o, int l, int r, int d, int op) {
spread(o);
if (l <= t[o].l && t[o].r <= r) {
if (op == 1) {
t[o].sum = (ll)(t[o].sum * d) % mod;
t[o].p = t[o].l == t[o].r ? 1 : ((ll)t[o].p * d) % mod;
}
else {
t[o].sum = (ll)((ll)t[o].sum + (ll)(d) * (t[o].r - t[o].l + 1)) % mod;
t[o].add = t[o].l == t[o].r ? 0 : (t[o].add + d) % mod;
}
return;
}
int mid = (t[o].l + t[o].r) >> 1;
if (mid >= l)change(le, l, r, d, op);
if (r > mid) change(ri, l, r, d, op);
update(o);
}
ll ask(int o, int l, int r) {
if (l <= t[o].l && r >= t[o].r)
return t[o].sum;
spread(o);
int mid = (t[o].l + t[o].r) >> 1;
if (mid >= r) return ask(le, l, r);
else if (mid < l) return ask(ri, l, r);
else return (ask(le, l, mid) + ask(ri, mid + 1, r)) % mod;
}
int main()
{
scanf("%d%d%lld", &n, &m, &mod);
build(1, 1, n);
while (m--)
{
int op, l, r, k;
assert(scanf("%d%d%d", &op, &l, &r) == 3);
if (op != 3) {
assert(scanf("%d", &k) == 1);
change(1, l, r, k, op);
#ifdef DEBUG
_rep(i, 1, n) cout << ask(1, i, i) << " ";
cout << endl;
#endif
}
else {
#ifdef DEBUG
ll out = 0;
_rep(i, l, r) {
out += ask(1, i, i);
out %= mod;
}
cout << "ans -->" << out << endl;
_rep(i, 1, n) {
cout << ask(1, i, i) << " ";
}
cout << endl;
#endif
printf("%lld\n", ask(1, l, r));
}
}
}