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

#include <bits/stdc++.h>
using namespace std;
using lint = long long;
constexpr lint inf = 1LL << 60;
constexpr lint mod = 998244353;
// constexpr lint mod = 1000000007;

template <lint mod> struct modint {
  lint v;
  constexpr modint(lint t = 0) noexcept {
    v = t % mod;
    if (v < 0)
      v += mod;
  }
  constexpr modint pow(lint k) const {
    modint res(1), tmp(v);
    while (k) {
      if (k & 1)
        res *= tmp;
      tmp *= tmp;
      k >>= 1;
    }
    return res;
  }
  static modint add_identity() { return modint(0); }
  static modint mul_identity() { return modint(1); }
  constexpr modint inv() const { return pow(mod - 2); }

  constexpr modint &operator+=(const modint a) noexcept {
    v += a.v;
    if (v >= mod)
      v -= mod;
    return *this;
  }
  constexpr modint &operator-=(const modint a) noexcept {
    v += mod - a.v;
    if (v >= mod)
      v -= mod;
    return *this;
  }
  constexpr modint &operator*=(const modint a) noexcept {
    v = v * a.v % mod;
    return *this;
  }
  constexpr modint &operator/=(const modint a) noexcept {
    return (*this) *= a.inv();
  }

  constexpr modint operator+(const modint a) const noexcept {
    return modint(v) += a;
  };
  constexpr modint operator-(const modint a) const noexcept {
    return modint(v) -= a;
  };
  constexpr modint operator*(const modint a) const noexcept {
    return modint(v) *= a;
  };
  constexpr modint operator/(const modint a) const noexcept {
    return modint(v) /= a;
  };
  constexpr modint operator-() const noexcept {
    return v ? modint(mod - v) : modint(v);
  }

  constexpr bool operator==(const modint a) const noexcept { return v == a.v; }
  constexpr bool operator!=(const modint a) const noexcept { return v != a.v; }
  constexpr bool operator<(const modint a) const noexcept { return v < a.v; }
};
using mint = modint<mod>;
ostream &operator<<(ostream &os, mint m) { return os << m.v; }

template <typename T = lint> struct SegmentTreeLazy {
private:
  using F = function<T(T, T, lint)>;
  int n;
  vector<T> node, lazy;
  vector<bool> lazyFlag;
  F func;
  T unit;
  vector<lint> sizes, ssum;
  vector<mint> nines;

public:
  SegmentTreeLazy(int sz, F func, T unit) : func(func), unit(unit) {
    n = 1;
    while (n < sz)
      n *= 2;
    node.assign(2 * n - 1, unit);
    lazy.assign(2 * n - 1, unit);
    lazyFlag.resize(2 * n - 1, false);
  }
  SegmentTreeLazy(vector<T> v, F func, T unit) : func(func), unit(unit) {
    int sz = int(v.size());
    n = 1;
    while (n < sz)
      n *= 2;
    nines.resize(n + 10);
    for (int i = 0; i < n + 10; ++i) {
      nines[i] = (mint(10).pow(i) - 1) / 9;
    }
    node.resize(2 * n - 1, unit);
    lazy.resize(2 * n - 1, unit);
    sizes.resize(2 * n - 1, 0);
    for (int i = 0; i < n - 1 + sz; ++i) {
      sizes[i] = 1;
    }
    ssum.resize(n, 0);
    for (int i = 0; i < sz; ++i) {
      ssum[i] = 1;
    }
    for (int i = 1; i < n; ++i) {
      ssum[i] += ssum[i - 1];
    }
    lazyFlag.resize(2 * n - 1, false);

    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--) {
      sizes[i] = sizes[i * 2 + 1] + sizes[i * 2 + 2];
      node[i] = func(node[i * 2 + 1], node[i * 2 + 2], sizes[i * 2 + 2]);
    }
  }
  void lazyEvaluate(int k, int l, int r) {
    if (lazyFlag[k]) {
      node[k] = nines[sizes[k]] * lazy[k];
      if (r - l > 1) {
        lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
        lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
      }
      lazyFlag[k] = false;
      // lazy[k]     = 0;
    }
  }
  // replace nodes with x in [a, b)
  void update(int a, int b, T x, int k = 0, int l = 0, int r = -1) {
    if (r < 0)
      r = n;
    lazyEvaluate(k, l, r);
    if (b <= l || r <= a)
      return;
    if (a <= l && r <= b) {
      // mint nv     = (mint(10).pow(sizes[k]) - 1) / 9 * x;
      lazy[k] = x;
      lazyFlag[k] = true;
      lazyEvaluate(k, l, r);
    } else {
      const int mid = (l + r) / 2;
      update(a, b, x, 2 * k + 1, l, mid);
      update(a, b, x, 2 * k + 2, mid, r);
      node[k] = func(node[2 * k + 1], node[2 * k + 2], sizes[2 * k + 1]);
    }
  }
  // get func() in [a, b)
  T query(int a, int b, int k = 0, int l = 0, int r = -1) {
    if (r < 0)
      r = n;
    lazyEvaluate(k, l, r);
    if (b <= l || r <= a)
      return unit;
    if (a <= l && r <= b)
      return node[k];
    T vl = query(a, b, 2 * k + 1, l, (l + r) / 2);
    T vr = query(a, b, 2 * k + 2, (l + r) / 2, r);
    lint nr = ssum[r - 1] - ssum[max(0, (l + r) / 2 - 1)];
    return func(vl, vr, nr);
  }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  lint n, q;
  cin >> n >> q;
  vector<mint> init(n, 1);
  vector<mint> tens(200010, 0);
  for (int i = 0; i < 200010; ++i) {
    tens[i] = mint(10).pow(i);
  }
  auto f = [&](mint l, mint r, lint nr) {
    if (nr == 0)
      return l;
    else
      return tens[nr] * l + r;
  };
  const mint unit = 0;
  SegmentTreeLazy<mint> seg(init, f, unit);
  for (int i = 0; i < q; ++i) {
    int l, r, d;
    cin >> l >> r >> d;
    l--, r--;
    seg.update(l, r + 1, d);
    cout << seg.query(0, n) << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
using lint = long long;
constexpr lint inf = 1LL << 60;
constexpr lint mod = 998244353;
// constexpr lint mod = 1000000007;

template <lint mod> struct modint {
  lint v;
  constexpr modint(lint t = 0) noexcept {
    v = t % mod;
    if (v < 0)
      v += mod;
  }
  constexpr modint pow(lint k) const {
    modint res(1), tmp(v);
    while (k) {
      if (k & 1)
        res *= tmp;
      tmp *= tmp;
      k >>= 1;
    }
    return res;
  }
  static modint add_identity() { return modint(0); }
  static modint mul_identity() { return modint(1); }
  constexpr modint inv() const { return pow(mod - 2); }

  constexpr modint &operator+=(const modint a) noexcept {
    v += a.v;
    if (v >= mod)
      v -= mod;
    return *this;
  }
  constexpr modint &operator-=(const modint a) noexcept {
    v += mod - a.v;
    if (v >= mod)
      v -= mod;
    return *this;
  }
  constexpr modint &operator*=(const modint a) noexcept {
    v = v * a.v % mod;
    return *this;
  }
  constexpr modint &operator/=(const modint a) noexcept {
    return (*this) *= a.inv();
  }

  constexpr modint operator+(const modint a) const noexcept {
    return modint(v) += a;
  };
  constexpr modint operator-(const modint a) const noexcept {
    return modint(v) -= a;
  };
  constexpr modint operator*(const modint a) const noexcept {
    return modint(v) *= a;
  };
  constexpr modint operator/(const modint a) const noexcept {
    return modint(v) /= a;
  };
  constexpr modint operator-() const noexcept {
    return v ? modint(mod - v) : modint(v);
  }

  constexpr bool operator==(const modint a) const noexcept { return v == a.v; }
  constexpr bool operator!=(const modint a) const noexcept { return v != a.v; }
  constexpr bool operator<(const modint a) const noexcept { return v < a.v; }
};
using mint = modint<mod>;
ostream &operator<<(ostream &os, mint m) { return os << m.v; }

template <typename T = lint> struct SegmentTreeLazy {
private:
  using F = function<T(T, T, lint)>;
  int n;
  vector<T> node, lazy;
  vector<bool> lazyFlag;
  F func;
  T unit;
  vector<lint> sizes, ssum;

public:
  SegmentTreeLazy(int sz, F func, T unit) : func(func), unit(unit) {
    n = 1;
    while (n < sz)
      n *= 2;
    node.assign(2 * n - 1, unit);
    lazy.assign(2 * n - 1, unit);
    lazyFlag.resize(2 * n - 1, false);
  }
  SegmentTreeLazy(vector<T> v, F func, T unit) : func(func), unit(unit) {
    int sz = int(v.size());

    n = 1;
    while (n < sz)
      n *= 2;
    node.resize(2 * n - 1, unit);
    lazy.resize(2 * n - 1, unit);
    sizes.resize(2 * n - 1, 0);
    for (int i = 0; i < n - 1 + sz; ++i) {
      sizes[i] = 1;
    }
    ssum.resize(n, 0);
    for (int i = 0; i < sz; ++i) {
      ssum[i] = 1;
    }
    for (int i = 1; i < n; ++i) {
      ssum[i] += ssum[i - 1];
    }
    lazyFlag.resize(2 * n - 1, false);

    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--) {
      sizes[i] = sizes[i * 2 + 1] + sizes[i * 2 + 2];
      node[i] = func(node[i * 2 + 1], node[i * 2 + 2], sizes[i * 2 + 2]);
    }
  }
  void lazyEvaluate(int k, int l, int r) {
    if (lazyFlag[k]) {
      node[k] = (mint(10).pow(sizes[k]) - 1) / 9 * lazy[k];
      if (r - l > 1) {
        lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
        lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
      }
      lazyFlag[k] = false;
      // lazy[k]     = 0;
    }
  }
  // replace nodes with x in [a, b)
  void update(int a, int b, T x, int k = 0, int l = 0, int r = -1) {
    if (r < 0)
      r = n;
    lazyEvaluate(k, l, r);
    if (b <= l || r <= a)
      return;
    if (a <= l && r <= b) {
      // mint nv     = (mint(10).pow(sizes[k]) - 1) / 9 * x;
      lazy[k] = x;
      lazyFlag[k] = true;
      lazyEvaluate(k, l, r);
    } else {
      const int mid = (l + r) / 2;
      update(a, b, x, 2 * k + 1, l, mid);
      update(a, b, x, 2 * k + 2, mid, r);
      node[k] = func(node[2 * k + 1], node[2 * k + 2], sizes[2 * k + 1]);
    }
  }
  // get func() in [a, b)
  T query(int a, int b, int k = 0, int l = 0, int r = -1) {
    if (r < 0)
      r = n;
    lazyEvaluate(k, l, r);
    if (b <= l || r <= a)
      return unit;
    if (a <= l && r <= b)
      return node[k];
    T vl = query(a, b, 2 * k + 1, l, (l + r) / 2);
    T vr = query(a, b, 2 * k + 2, (l + r) / 2, r);
    lint nr = ssum[r - 1] - ssum[max(0, (l + r) / 2 - 1)];
    return func(vl, vr, nr);
  }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  lint n, q;
  cin >> n >> q;
  vector<mint> init(n, 1);
  auto f = [](mint l, mint r, lint nr) {
    if (nr == 0)
      return l;
    else
      return mint(10).pow(nr) * l + r;
  };
  const mint unit = 0;
  SegmentTreeLazy<mint> seg(init, f, unit);
  for (int i = 0; i < q; ++i) {
    int l, r, d;
    cin >> l >> r >> d;
    l--, r--;
    seg.update(l, r + 1, d);
    cout << seg.query(0, n) << endl;
  }
  return 0;
}