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

#include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)
#define RREP(i, n) for (int i = (int)(n)-1; i >= 0; --i)
#define FOR(i, a, n) for (int i = (a); i < (n); ++i)
#define RFOR(i, a, n) for (int i = (int)(n)-1; i >= (a); --i)

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()

#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl;

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[";
  REP(i, SZ(v)) {
    if (i)
      os << ", ";
    os << v[i];
  }
  return os << "]";
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << " " << p.second << ")";
}

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 998244353;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;

template <typename M, typename OM = M> struct LazySegmentTree {

  /**
   * @brief コンストラクタ. O(n)
   * @param[in] n 遅延セグ木のサイズ.
   * @param[in] f 要素モノイドの演算.
   * @param[in] g 要素に作用素を作用させる演算.
   * @param[in] h 作用素モノイドの演算.
   * @param[in] e 要素モノイドの単位元.
   * @param[in] oe 作用素モノイドの単位元.
   * @details 使い方
   *   e.g. Range Add Range Sum
   *   LazySegmentTree<int> segt(
   *            n,
   *            [](int a,int b){ return a+b; },
   *            [](int a,int b,int w){ return a + b*w; },
   *            [](int a,int b){ return a+b; },
   *            0, 0);
   *               // 全て単位元で初期化される.
   */
  LazySegmentTree(int n, const function<M(M, M)> &f,
                  const function<M(M, OM, int)> &g,
                  const function<OM(OM, OM)> &h, const M &e, const OM &oe)
      : n(n), f(f), g(g), h(h), e(e), oe(oe) {
    sz = 1;
    while (sz < n)
      sz <<= 1;
    data.assign(2 * sz, e);
    lazy.assign(2 * sz, oe);
  }

  /**
   * @brief 全体に初期値を入れる. O(n)
   * @param[in] v 要素モノイドのvector. 初期化する.
   * @details 使い方
   *   segt.build(vector<int>(n, INF));
   */
  void build(const vector<M> &v) {
    assert(v.size() <= n);
    for (int i = 0; i < v.size(); ++i) {
      data[i + sz] = v[i];
    }
    for (int i = sz - 1; i > 0; --i) {
      data[i] = f(data[2 * i], data[2 * i + 1]);
    }
  }

  /**
   * @brief 指定した区間に作用素x を作用させる. O(log n)
   * @param[in] l, r 区間[l, r) に作用させる.
   * @param[in] x 作用素モノイドの元.
   * @details 使い方
   *   e.g. Range Update
   *   int l, r, x; // 区間[l, r) をx に更新したい.
   *   segt.update(l, r, x);
   */
  void update(int a, int b, const OM &x) { update(a, b, x, 1, 0, sz); }

  /**
   * @brief 指定した区間に取得クエリを実行する. O(log n)
   * @param[in] l, r 区間[l, r) を取得する.
   * @return 取得した値.
   * @details 使い方
   *   e.g. Range Minimum
   *   int l, r; // 区間[l, r) のminを取得したい.
   *   cout << segt.query(l, r) << endl;
   */
  M query(int a, int b) { return query(a, b, 1, 0, sz); }

  /**
   * @brief 指定したindexの要素を取得. O(1)
   * @param[in] i 取得したい要素のindex
   * @return 取得した値.
   */
  M operator[](int i) { return query(i, i + 1); }

  /**
   * @brief vector みたいに出力.
   */
  friend ostream &operator<<(ostream &os, LazySegmentTree &s) {
    os << "[";
    for (int i = 0; i < s.n; ++i) {
      if (i)
        os << " ";
      os << s[i];
    }
    return os << "]";
  }

  int n, sz;
  vector<M> data;
  vector<OM> lazy;
  const function<M(M, M)> f;
  const function<M(M, OM, int)> g;
  const function<OM(OM, OM)> h;
  const M e;
  const OM oe;

  void propagate(int k, int len) {
    if (lazy[k] == oe)
      return;
    if (k < sz) {
      lazy[2 * k] = h(lazy[2 * k], lazy[k]);
      lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
    }
    data[k] = g(data[k], lazy[k], len);
    lazy[k] = oe;
  }

  void update(int a, int b, const OM &x, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a or b <= l)
      return;
    else if (a <= l and r <= b) {
      lazy[k] = h(lazy[k], x);
      propagate(k, r - l);
    } else {
      update(a, b, x, 2 * k, l, (l + r) >> 1);
      update(a, b, x, 2 * k + 1, (l + r) >> 1, r);
      data[k] = f(data[2 * k], data[2 * k + 1]);
    }
  }

  M query(int a, int b, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a or b <= l)
      return e;
    else if (a <= l and r <= b)
      return data[k];
    else
      return f(query(a, b, 2 * k, l, (l + r) >> 1),
               query(a, b, 2 * k + 1, (l + r) >> 1, r));
  }
};

ll powm(ll a, ll n, ll m) {
  ll ret = 1;
  while (n > 0) {
    if (n & 1)
      (ret *= a) %= m;
    (a *= a) %= m;
    n >>= 1;
  }
  return ret;
}

ll invm(ll a, ll m) { return powm(a, m - 2, m); }

const ll inv9 = invm(9, MOD);
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  int n, q;
  cin >> n >> q;

  using P = pair<ll, ll>;
  LazySegmentTree<P, P> st(
      n,
      [](P a, P b) {
        return make_pair((a.first * powm(10, b.second, MOD) % MOD + b.first) %
                             MOD,
                         a.second + b.second);
      },
      [](P a, P b, int w) {
        const ll val =
            b.first * ((powm(10, w, MOD) + MOD - 1) % MOD) % MOD * inv9 % MOD;
        return make_pair(val, w);
      },
      [](P a, P b) { return b; }, {0, 0}, {-INF, -INF});
  vector<P> v(n, {1, 1});
  st.build(v);

  REP(i, q) {
    int l, r, d;
    cin >> l >> r >> d;
    l--;
    st.update(l, r, {d, r - l});
    cout << st.query(0, n).first << endl;
  }

  ll ans = 0;

  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)
#define RREP(i, n) for (int i = (int)(n)-1; i >= 0; --i)
#define FOR(i, a, n) for (int i = (a); i < (n); ++i)
#define RFOR(i, a, n) for (int i = (int)(n)-1; i >= (a); --i)

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()

#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl;

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[";
  REP(i, SZ(v)) {
    if (i)
      os << ", ";
    os << v[i];
  }
  return os << "]";
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << " " << p.second << ")";
}

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 998244353;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;

template <typename M, typename OM = M> struct LazySegmentTree {

  /**
   * @brief コンストラクタ. O(n)
   * @param[in] n 遅延セグ木のサイズ.
   * @param[in] f 要素モノイドの演算.
   * @param[in] g 要素に作用素を作用させる演算.
   * @param[in] h 作用素モノイドの演算.
   * @param[in] e 要素モノイドの単位元.
   * @param[in] oe 作用素モノイドの単位元.
   * @details 使い方
   *   e.g. Range Add Range Sum
   *   LazySegmentTree<int> segt(
   *            n,
   *            [](int a,int b){ return a+b; },
   *            [](int a,int b,int w){ return a + b*w; },
   *            [](int a,int b){ return a+b; },
   *            0, 0);
   *               // 全て単位元で初期化される.
   */
  LazySegmentTree(int n, const function<M(M, M)> &f,
                  const function<M(M, OM, int)> &g,
                  const function<OM(OM, OM)> &h, const M &e, const OM &oe)
      : n(n), f(f), g(g), h(h), e(e), oe(oe) {
    sz = 1;
    while (sz < n)
      sz <<= 1;
    data.assign(2 * sz, e);
    lazy.assign(2 * sz, oe);
  }

  /**
   * @brief 全体に初期値を入れる. O(n)
   * @param[in] v 要素モノイドのvector. 初期化する.
   * @details 使い方
   *   segt.build(vector<int>(n, INF));
   */
  void build(const vector<M> &v) {
    assert(v.size() <= n);
    for (int i = 0; i < v.size(); ++i) {
      data[i + sz] = v[i];
    }
    for (int i = sz - 1; i > 0; --i) {
      data[i] = f(data[2 * i], data[2 * i + 1]);
    }
  }

  /**
   * @brief 指定した区間に作用素x を作用させる. O(log n)
   * @param[in] l, r 区間[l, r) に作用させる.
   * @param[in] x 作用素モノイドの元.
   * @details 使い方
   *   e.g. Range Update
   *   int l, r, x; // 区間[l, r) をx に更新したい.
   *   segt.update(l, r, x);
   */
  void update(int a, int b, const OM &x) { update(a, b, x, 1, 0, sz); }

  /**
   * @brief 指定した区間に取得クエリを実行する. O(log n)
   * @param[in] l, r 区間[l, r) を取得する.
   * @return 取得した値.
   * @details 使い方
   *   e.g. Range Minimum
   *   int l, r; // 区間[l, r) のminを取得したい.
   *   cout << segt.query(l, r) << endl;
   */
  M query(int a, int b) { return query(a, b, 1, 0, sz); }

  /**
   * @brief 指定したindexの要素を取得. O(1)
   * @param[in] i 取得したい要素のindex
   * @return 取得した値.
   */
  M operator[](int i) { return query(i, i + 1); }

  /**
   * @brief vector みたいに出力.
   */
  friend ostream &operator<<(ostream &os, LazySegmentTree &s) {
    os << "[";
    for (int i = 0; i < s.n; ++i) {
      if (i)
        os << " ";
      os << s[i];
    }
    return os << "]";
  }

  int n, sz;
  vector<M> data;
  vector<OM> lazy;
  const function<M(M, M)> f;
  const function<M(M, OM, int)> g;
  const function<OM(OM, OM)> h;
  const M e;
  const OM oe;

  void propagate(int k, int len) {
    if (lazy[k] == oe)
      return;
    if (k < sz) {
      lazy[2 * k] = h(lazy[2 * k], lazy[k]);
      lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
    }
    data[k] = g(data[k], lazy[k], len);
    lazy[k] = oe;
  }

  void update(int a, int b, const OM &x, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a or b <= l)
      return;
    else if (a <= l and r <= b) {
      lazy[k] = h(lazy[k], x);
      propagate(k, r - l);
    } else {
      update(a, b, x, 2 * k, l, (l + r) >> 1);
      update(a, b, x, 2 * k + 1, (l + r) >> 1, r);
      data[k] = f(data[2 * k], data[2 * k + 1]);
    }
  }

  M query(int a, int b, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a or b <= l)
      return e;
    else if (a <= l and r <= b)
      return data[k];
    else
      return f(query(a, b, 2 * k, l, (l + r) >> 1),
               query(a, b, 2 * k + 1, (l + r) >> 1, r));
  }
};

ll powm(ll a, ll n, ll m) {
  ll ret = 1;
  while (n > 0) {
    if (n & 1)
      (ret *= a) %= m;
    (a *= a) %= m;
    n >>= 1;
  }
  return ret;
}

ll invm(ll a, ll m) { return powm(a, m - 2, m); }

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  int n, q;
  cin >> n >> q;

  using P = pair<ll, ll>;
  LazySegmentTree<P, P> st(
      n,
      [](P a, P b) {
        return make_pair((a.first * powm(10, b.second, MOD) % MOD + b.first) %
                             MOD,
                         a.second + b.second);
      },
      [](P a, P b, int w) {
        ll val = b.first * ((powm(10, w, MOD) + MOD - 1) % MOD) % MOD *
                 invm(9, MOD) % MOD;
        return make_pair(val, w);
      },
      [](P a, P b) { return b; }, {0, 0}, {-INF, -INF});
  vector<P> v(n, {1, 1});
  st.build(v);

  REP(i, q) {
    int l, r, d;
    cin >> l >> r >> d;
    l--;
    st.update(l, r, {d, r - l});
    cout << st.query(0, n).first << endl;
  }

  ll ans = 0;

  return 0;
}