phyllo’s algorithm note

レッドコーダーへの道のりは遠い。休んでる場合じゃない!

ABL E. Replace Digits

問題

長さNの文字列Sがあり、すべての文字は「1」になっている。
Q回、整数L, Rと数字Dが与えられるのでいかに答えよ。

  • L番目からR番目の文字をすべてDに書き換え、文字列Sを10進数で書いた整数とみなした値を998,224,353で割ったあまりで表示せよ

制約

  • 1 <= N, Q <= 200,000
  • 1 <= L <= R <= N
  • 1 <= D <= 9

解法

範囲更新、範囲取得したいので、遅延セグメント木の適用を考える。

ある範囲の文字列を10進数で表示してmodをとったものaを考える。
隣り合う範囲のaとa'は、その位置関係で連結した場合、aを10^{a'の範囲の長さ}倍したものとa'を合わせれば求められる。
したがって、モノイドとしては、「その範囲の数字列を10進数とみなしてmodをとった値」と「範囲の長さ」を保持すれば良い。

struct S { mint a; int size; }
S op(S l, S r) {
  mint x = mint(10).pow(r.size);
  return S{l.a*x+r.a, l.size+r.size};
}
S e(){
  return S{0,0};
}

これで、表示する答えは、seg.all_prod().a.val()で取得できる。


次に、範囲更新を考える。
「L~Rの数字をDに書き換える」ので、
あるモノイドSに作用させた場合、サイズは変わらず、S.aは1111....11111にDをかけたものになる。
作用素F'に作用素Fが作用した場合は、後に適用したほうのものになってほしいので、作用素に適用タイミングiをもたせて、それが大きい(後で更新したほう)にする。

struct F { int a, i; };
S mapping(F l, S r){
  if(l.i == -1) return r;
  return S{ones[r.size] * l.a, r.size};
}
F composition(F l, F r){
  if(l.i < r.i) return r;
  return l;
}
F id(){ return F{0, -1}; }

あとは、クエリごとに、seg.apply()してからseg.all_prod().a.val()を表示すればよい。