F - Max Matrix - 第二回日本最強プログラマー学生選手権
問題
- 長さ N の数列 a と、長さ M の数列 b がある
- 最初、a,b の要素は全て 0
- Q 個のクエリを処理する。i 個目のクエリでは Ti,Xi,Yi が与えられる
- Ti=1 のとき、aXi を Yi に置き換える
- Ti=2 のとき、bXi を Yi に置き換える
- 毎回のクエリの処理直後に N∑i=1M∑j=1max(ai,bj) の値を出力する
- 1≤N,M≤2×105
- 1≤Q≤2×105
- 1≤Yi≤108
解法
最初、全要素が0なので答えは言うまでも無く0。
たとえば a の1個 ai を 5 から 10 に変えたときに、全体の答えがどうなるか考えると、
- b の、10 より小さい値について
- その個数分だけ、新規に max(ai,bj)=10 になる組が増える
- 答えが「該当個数×10」増加する
- b の、5 以下の値について
- その個数分だけ、今まで max(ai,bj)=5 だった組が上に変わる
- 答えが「該当個数×5」減少する
- b の、5 より大きく 10 より小さい値について
- その総和だけ、max(ai,bj)=bj として今まで答えに寄与していた分が無くなる
- 答えが「該当する bj の総和」分だけ減少する
これで全て。
なので、差分だけ更新していくことで、クエリに高速に答えられそう。
なお、10 から 5 に変わるなど値が減少するときは、3つめの増加と減少が逆転する。
範囲の個数や総和を求めたいので、セグメント木やFenwick Treeで管理すればよい。
「a 用、b 用」「個数用、総和用」で合計4つ、必要になる。
Yi の取り得る範囲が 108 と大きいので、座標圧縮の必要がある。
今回は「ai を Yold から Ynew に変えるとき、この間の個数や総和」が求まればよい、つまり Yi の大小関係さえ保たれていれば範囲指定できるので、
Yi として出てくる値をソートして小さい順に 0,1,2,... に対応させれば、Q の長さ 2×105 として扱うことができる。
範囲の境界(以下なのか未満なのか、など)に注意。
どちらでもよいが、ai=bj となる bj があり、今まで max(ai,bj)=bj だった場合、それを「max(ai,bj)=ai に変わったと見なし、更新対象に含めるのか(同じ値が引かれ、足されるので実質は変化ない)」「変化無しとして更新対象に含めないのか」は、3種類の更新の中で統一しておく必要がある。