概述
本题作为模板题实在是太屈才了, 是一道很好的题目,做完以后本人对线段树有了更深的理解。单就此题而言,两种修改操作是互相影响的,修改乘法的时候是要先考虑加法的修改。为了避免这种先加后乘的影响,我们在打 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<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#include<iostream>
#include<climits>
#include<queue>
#include<cassert>
#include<iomanip>
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#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)
//#define DEBUG
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()
{
/*FILE *O = freopen("C:\Users\Jason.Z\Desktop\in.txt", "r", stdin);
FILE *W = freopen("C:\Users\Jason.Z\Desktop\out.txt", "w", stdout);
assert(O != NULL && W != NULL);
clock_t S = clock();*/
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 // DEBUG
}
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 // DEBUG
printf("%lldn", ask(1, l, r));
}
}
//clock_t E = clock();
//freopen("CON", "w", stdout);
//cout << 1000.0 * (E - S) / CLOCKS_PER_SEC<< "ms" << endl;
//return 0;
}
/*
8 10 571373
5929 7152 8443 6028 8580 5449 8473 4237
2 4 8 4376
1 2 8 9637
2 2 6 7918
2 5 8 5681
3 2 8
1 1 5 6482
3 1 5
1 5 8 8701
2 5 8 7992
2 5 8 7806
*/
最后
以上就是积极黄豆为你收集整理的洛谷 - P3373 线段树区间-修改(进阶)直接上码 (我知道你们只看这个) :的全部内容,希望文章能够帮你解决洛谷 - P3373 线段树区间-修改(进阶)直接上码 (我知道你们只看这个) :所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复