线段树复习笔记

Published on7/29/2025
Created on 10/21/2021

By Chesium 2021/10/21

  1. 若无标记,则直接返回。
  2. s=ts=t,则标记无作用,也没有区间用于下传,直接返回。
  3. 求出 mm ,根据区间范围修改 d[2p]d[2p]d[2p+1]d[2p+1] 的值
  4. 更新子区间的懒惰标记 b[2p]b[2p]b[2p+1]b[2p+1]
  5. 清除自身的懒惰标记。
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
//---//
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

typedef unsigned int u;
typedef long long ll;
typedef unsigned long long llu;

#define rep(i, a, b) for (ll i = a; i < b; i++)
#define REP(i, a, b) for (ll i = a; i <= b; i++)
#define per(i, b, a) for (ll i = b; i >= a; i--)

// P3372 【模板】线段树 1

#define get_mid ll m = s + ((t - s) >> 1)

const ll N = 1e5 + 10;

ll a[N], d[4 * N], b[4 * N];
bool lz[4 * N];

void build(ll s, ll t, ll p) {
  if (s == t) {
    d[p] = a[s];
    return;
  }
  get_mid;
  build(s, m, 2 * p);
  build(m + 1, t, 2 * p + 1);
  d[p] = d[2 * p] + d[2 * p + 1];
}

ll push_down(ll s, ll t, ll p) {
  get_mid;
  if (s == t || (!lz[p])) return m;
  b[2 * p] += b[p];
  b[2 * p + 1] += b[p];
  d[2 * p] += b[p] * (m - s + 1);
  d[2 * p + 1] += b[p] * (t - m);
  lz[2 * p] = true;
  lz[2 * p + 1] = true;
  b[p] = 0;
  lz[p] = false;
  return m;
}

void update(ll l, ll r, ll c, ll s, ll t, ll p) {
  if (l <= s && t <= r) {
    d[p] += (t - s + 1) * c;
    b[p] += c;
    lz[p] = true;
    return;
  }
  ll m = push_down(s, t, p);
  if (l <= m) update(l, r, c, s, m, 2 * p);
  if (r > m) update(l, r, c, m + 1, t, 2 * p + 1);
  d[p] = d[2 * p] + d[2 * p + 1];
}

ll query(ll l, ll r, ll s, ll t, ll p) {
  if (l <= s && t <= r) {
    return d[p];
  }
  ll sum = 0, m = push_down(s, t, p);
  if (l <= m) sum += query(l, r, s, m, 2 * p);
  if (r > m) sum += query(l, r, m + 1, t, 2 * p + 1);
  return sum;
}

signed main() {
  ll n, m, t, l, r, k;
  scanf("%lld%lld", &n, &m);
  REP(i, 1, n) scanf("%lld", &a[i]);
  build(1, n, 1);
  while (m--) {
    scanf("%lld%lld%lld", &t, &l, &r);
    if (t == 1) {
      scanf("%lld", &k);
      update(l, r, k, 1, n, 1);
    } else
      printf("%lld\n", query(l, r, 1, n, 1));
  }
}

// https://www.luogu.com.cn/record/60473191
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
//---//
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

typedef unsigned int u;
typedef long long ll;
typedef unsigned long long llu;

#define rep(i, a, b) for (ll i = a; i < b; i++)
#define REP(i, a, b) for (ll i = a; i <= b; i++)
#define per(i, b, a) for (ll i = b; i >= a; i--)

// P3372 【模板】线段树 2

#define get_mid ll m = s + ((t - s) >> 1)

const ll N = 1e5 + 10;

ll mod, a[N], d[4 * N], add[4 * N], mul[4 * N];
bool lz[4 * N];

void build(ll s, ll t, ll p) {
  mul[p] = 1;
  if (s == t) {
    d[p] = a[s];
    return;
  }
  get_mid;
  build(s, m, 2 * p);
  build(m + 1, t, 2 * p + 1);
  d[p] = (d[2 * p] + d[2 * p + 1]) % mod;
}

ll push_down(ll s, ll t, ll p) {
  get_mid;
  if (s == t || (!lz[p])) return m;
  d[2 * p] = (add[p] * (m - s + 1) % mod + d[2 * p] * mul[p] % mod) % mod;
  d[2 * p + 1] = (add[p] * (t - m) % mod + d[2 * p + 1] * mul[p] % mod) % mod;
  add[2 * p] = (add[2 * p] * mul[p] % mod + add[p]) % mod;
  add[2 * p + 1] = (add[2 * p + 1] * mul[p] % mod + add[p]) % mod;
  mul[2 * p] = mul[2 * p] * mul[p] % mod;
  mul[2 * p + 1] = mul[2 * p + 1] * mul[p] % mod;
  lz[2 * p] = true;
  lz[2 * p + 1] = true;
  add[p] = 0;
  mul[p] = 1;
  lz[p] = false;
  return m;
}

void update_add(ll l, ll r, ll c, ll s, ll t, ll p) {
  if (l <= s && t <= r) {
    d[p] = ((t - s + 1) * c % mod + d[p]) % mod;
    add[p] = (c + add[p]) % mod;
    lz[p] = true;
    return;
  }
  ll m = push_down(s, t, p);
  if (l <= m) update_add(l, r, c, s, m, 2 * p);
  if (r > m) update_add(l, r, c, m + 1, t, 2 * p + 1);
  d[p] = (d[2 * p] + d[2 * p + 1]) % mod;
}

void update_mul(ll l, ll r, ll c, ll s, ll t, ll p) {
  if (l <= s && t <= r) {
    d[p] = d[p] * c % mod;
    add[p] = add[p] * c % mod;
    mul[p] = (mul[p] * c) % mod;
    lz[p] = true;
    return;
  }
  ll m = push_down(s, t, p);
  if (l <= m) update_mul(l, r, c, s, m, 2 * p);
  if (r > m) update_mul(l, r, c, m + 1, t, 2 * p + 1);
  d[p] = (d[2 * p] + d[2 * p + 1]) % mod;
}

ll query(ll l, ll r, ll s, ll t, ll p) {
  if (l <= s && t <= r) return d[p];
  ll sum = 0, m = push_down(s, t, p);
  if (l <= m) sum = (sum + query(l, r, s, m, 2 * p)) % mod;
  if (r > m) sum = (sum + query(l, r, m + 1, t, 2 * p + 1)) % mod;
  return sum;
}

signed main() {
  ll n, m, t, l, r, k;
  scanf("%lld%lld%lld", &n, &m, &mod);
  REP(i, 1, n) scanf("%lld", &a[i]);
  build(1, n, 1);
  while (m--) {
    scanf("%lld%lld%lld", &t, &l, &r);
    switch (t) {
      case 1:
        scanf("%lld", &k);
        update_mul(l, r, k, 1, n, 1);
        break;
      case 2:
        scanf("%lld", &k);
        update_add(l, r, k, 1, n, 1);
        break;
      case 3:
        printf("%lld\n", query(l, r, 1, n, 1));
        break;
    }
  }
}

// https://www.luogu.com.cn/record/60476253
  1. 线段树 - OI Wiki (oi-wiki.org)
  2. 【算法】线段树详解_Alexander的博客-CSDN博客_线段树算法
  3. 题解 P3373 【【模板】线段树 2】 - lqhsr 的博客 - 洛谷博客 (luogu.com.cn)
  4. 线段树 - 简书 (jianshu.com)