洛谷 - P3373 线段树区间-修改(进阶)

本题作为模板题实在是太屈才了, 是一道很好的题目,做完以后本人对线段树有了更深的理解。单就此题而言,两种修改操作是互相影响的,修改乘法的时候是要先考虑加法的修改。为了避免这种先加后乘的影响,我们在打 lazy-tag的时候要注意

  lson.add = (t[o].add + lson.add * t[o].p) % mod;

即乘法之前先把加法的 lazy_tag 先乘出来,然后再更新加法的lazy_tag,

洛谷 - P3373 线段树区间-修改(进阶)_第1张图片

洛谷 - P3373 线段树区间-修改(进阶)_第2张图片

直接上码 (我知道你们只看这个)



#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)
//#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("%lld\n", 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
*/

你可能感兴趣的:(数据结构)