Problem p02538 (C++) — buggy submission, verdict: Time Limit Exceeded

/*Hatsune Miku 4ever!*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define _for(i, a, b) for (int i = (a); i < b; i++)
#define _rep(i, a, b) for (int i = (a); i > b; i--)
#define INF 0x3f3f3f3f3f3f3f3f
#define lowbit(x) ((x) & (-x))
#define pb push_back
#define MIKU 39
#define Design ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define debug() printf("Miku Check OK!\\n")
#define bigmiku 3939393939
#define maxn 200039
#define maxe 1000003
const ll mod = 998244353;
vector<ll> der;
ll inv;
ll fpow(ll a, ll n, ll mod) {
  ll res = 1;
  while (n) {
    if (n & 1) {
      res = res % mod * a % mod;
    }
    a = a % mod * a % mod;
    n >>= 1;
  }
  return res;
}

struct SegTree {
  struct SegNode {
    // l,r代表的是该节点表示的原数组下标
    int l, r;
    // add为该区间懒惰标记
    ll add;
    // sum,max和min分别为原数组对应区间的和，最大值以及最小值
    ll val;
// x为线段树内部下标
#define l(x) tree[x].l
#define r(x) tree[x].r
#define val(x) tree[x].val
#define add(x) tree[x].add
  } tree[maxn << 2];
  void build(int p, int l, int r) {
    add(p) = 0;
    // p为线段树内部下标
    l(p) = l, r(p) = r;
    // 到达叶子节点
    if (l == r) {
      val(p) = der[l(p)];
      return;
    }
    int mid = (l + r) / 2;
    // 递归构造左右节点
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    // 左右节点维护完后开始维护父节点
    val(p) = ((val(p * 2) + val(p * 2 + 1)) % mod + mod) % mod;
  }
  // 懒惰标记下放
  void spread(int p) {
    if (add(p)) {
      ll d = add(p);
      val(p * 2) =
          d * inv % mod * ((der[l(p * 2)] - der[r(p * 2) + 1]) + mod) % mod;
      val(p * 2) %= mod;
      val(p * 2 + 1) = d * inv % mod *
                       ((der[l(p * 2 + 1)] - der[r(p * 2 + 1) + 1]) + mod) %
                       mod;
      val(p * 2 + 1) %= mod;

      add(p * 2) = add(p);
      add(p * 2 + 1) = add(p);
      add(p) = 0;
    }
  }
  void change(int p, int l, int r, ll d) {
    // 要修改区间完全包住当前节点区间
    if (l <= l(p) && r >= r(p)) {
      val(p) = d * inv % mod * ((der[l(p)] - der[r(p) + 1]) + mod) % mod;
      val(p) %= mod;
      add(p) = d;
      return;
    }
    // 否则下放当前节点懒惰标记
    spread(p);
    int mid = (l(p) + r(p)) / 2;
    /*如果要修改的区间左端点比当前节点代表区间的mid小则说明涉及到了
    左区间*/
    if (l <= mid)
      change(p * 2, l, r, d);
    // 右端同理
    if (r > mid)
      change(p * 2 + 1, l, r, d);
    val(p) = ((val(p * 2) + val(p * 2 + 1)) % mod + mod) % mod;
  }
} T;

int n, q;

int main() {
  scanf("%d%d", &n, &q);
  der.pb(1);
  _for(i, 1, n + 1) der.pb((der[i - 1] * 10) % mod);
  inv = (-9 + mod) % mod;
  inv = fpow(inv, mod - 2, mod);
  T.build(1, 0, n - 1);
  _for(i, 1, q + 1) {
    int L, R, D;
    scanf("%d%d%d", &L, &R, &D);
    L--, R--;
    L = n - 1 - L;
    R = n - 1 - R;
    swap(L, R);
    T.change(1, L, R, D);
    printf("%lld\\n", T.tree[1].val % mod);
  }
  return 0;
}

Error: TLE

Fixed submission:

/*Hatsune Miku 4ever!*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define _for(i, a, b) for (int i = (a); i < b; i++)
#define _rep(i, a, b) for (int i = (a); i > b; i--)
#define INF 0x3f3f3f3f3f3f3f3f
#define lowbit(x) ((x) & (-x))
#define pb push_back
#define MIKU 39
#define Design ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define debug() printf("Miku Check OK!\\n")
#define bigmiku 3939393939
#define maxn 200039
#define maxe 1000003
const ll mod = 998244353;

ll fpow(ll a, ll n, ll mod) {
  ll res = 1;
  while (n) {
    if (n & 1) {
      res = res % mod * a % mod;
    }
    a = a % mod * a % mod;
    n >>= 1;
  }
  return res;
}

struct SegTree {
  struct SegNode {
    // l,r代表的是该节点表示的原数组下标
    int l, r;
    // add为该区间懒惰标记
    ll add;
    // sum,max和min分别为原数组对应区间的和，最大值以及最小值
    ll val;
// x为线段树内部下标
#define l(x) tree[x].l
#define r(x) tree[x].r
#define val(x) tree[x].val
#define add(x) tree[x].add
  } tree[maxn << 2];
  void build(int p, int l, int r) {
    add(p) = 0;
    // p为线段树内部下标
    l(p) = l, r(p) = r;
    // 到达叶子节点
    if (l == r) {
      val(p) = fpow(10, l(p), mod);
      return;
    }
    int mid = (l + r) / 2;
    // 递归构造左右节点
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    // 左右节点维护完后开始维护父节点
    val(p) = ((val(p * 2) + val(p * 2 + 1)) % mod + mod) % mod;
  }
  // 懒惰标记下放
  void spread(int p) {
    if (add(p)) {
      ll d = add(p);
      val(p * 2) =
          d * fpow((-9 + mod) % mod, mod - 2, mod) % mod *
          (((fpow(10, l(p * 2), mod) - fpow(10, r(p * 2) + 1, mod)) + mod) %
           mod);
      val(p * 2) %= mod;
      val(p * 2 + 1) =
          d * fpow((-9 + mod) % mod, mod - 2, mod) % mod *
          (((fpow(10, l(p * 2 + 1), mod) - fpow(10, r(p * 2 + 1) + 1, mod)) +
            mod) %
           mod);
      val(p * 2 + 1) %= mod;

      add(p * 2) = add(p);
      add(p * 2 + 1) = add(p);
      add(p) = 0;
    }
  }
  void change(int p, int l, int r, ll d) {
    // 要修改区间完全包住当前节点区间
    if (l <= l(p) && r >= r(p)) {
      val(p) = d * fpow((-9 + mod) % mod, mod - 2, mod) % mod *
               (((fpow(10, l(p), mod) - fpow(10, r(p) + 1, mod)) + mod) % mod);
      val(p) %= mod;
      add(p) = d;
      return;
    }
    // 否则下放当前节点懒惰标记
    spread(p);
    int mid = (l(p) + r(p)) / 2;
    /*如果要修改的区间左端点比当前节点代表区间的mid小则说明涉及到了
    左区间*/
    if (l <= mid)
      change(p * 2, l, r, d);
    // 右端同理
    if (r > mid)
      change(p * 2 + 1, l, r, d);
    val(p) = ((val(p * 2) + val(p * 2 + 1)) % mod + mod) % mod;
  }
} T;

int n, q;

int main() {
  scanf("%d%d", &n, &q);
  T.build(1, 0, n - 1);
  _for(i, 1, q + 1) {
    int L, R, D;
    scanf("%d%d%d", &L, &R, &D);
    L--, R--;
    L = n - 1 - L;
    R = n - 1 - R;
    swap(L, R);
    T.change(1, L, R, D);
    printf("%lld\\n", T.tree[1].val % mod);
  }
  return 0;
}