Processing math: 27%

F - Max Matrix - 第二回日本最強プログラマー学生選手権

問題

  • 長さ N の数列 a と、長さ M の数列 b がある
  • 最初、a,b の要素は全て 0
  • Q 個のクエリを処理する。i 個目のクエリでは Ti,Xi,Yi が与えられる
    • Ti=1 のとき、aXiYi に置き換える
    • Ti=2 のとき、bXiYi に置き換える
    • 毎回のクエリの処理直後に Ni=1Mj=1max の値を出力する
  • 1 \le N,M \le 2 \times 10^5
  • 1 \le Q \le 2 \times 10^5
  • 1 \le Y_i \le 10^8

解法

最初、全要素が0なので答えは言うまでも無く0。

たとえば a の1個 a_i5 から 10 に変えたときに、全体の答えがどうなるか考えると、

  • b の、10 より小さい値について
    • その個数分だけ、新規に \max(a_i,b_j)=10 になる組が増える
      • 答えが「該当個数 \times 10」増加する
  • b の、5 以下の値について
    • その個数分だけ、今まで \max(a_i,b_j)=5 だった組が上に変わる
      • 答えが「該当個数 \times 5」減少する
  • b の、5 より大きく 10 より小さい値について
    • その総和だけ、\max(a_i,b_j)=b_j として今まで答えに寄与していた分が無くなる
      • 答えが「該当する b_j の総和」分だけ減少する

これで全て。
なので、差分だけ更新していくことで、クエリに高速に答えられそう。

なお、10 から 5 に変わるなど値が減少するときは、3つめの増加と減少が逆転する。

範囲の個数や総和を求めたいので、セグメント木やFenwick Treeで管理すればよい。
a 用、b 用」「個数用、総和用」で合計4つ、必要になる。

Y_i の取り得る範囲が 10^8 と大きいので、座標圧縮の必要がある。
今回は「a_iY_{old} から Y_{new} に変えるとき、この間の個数や総和」が求まればよい、つまり Y_i の大小関係さえ保たれていれば範囲指定できるので、 Y_i として出てくる値をソートして小さい順に 0,1,2,... に対応させれば、Q の長さ 2 \times 10^5 として扱うことができる。

範囲の境界(以下なのか未満なのか、など)に注意。
どちらでもよいが、a_i=b_j となる b_j があり、今まで \max(a_i,b_j)=b_j だった場合、それを「\max(a_i,b_j)=a_i に変わったと見なし、更新対象に含めるのか(同じ値が引かれ、足されるので実質は変化ない)」「変化無しとして更新対象に含めないのか」は、3種類の更新の中で統一しておく必要がある。

Python3

programming_algorithm/contest_history/atcoder/2021/0417_jsc2021/f.txt · 最終更新: 2021/04/18 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0