区間の種類数を答えるクエリ
Page content
問題設定
以下のようなクエリを考えます.
- \(n\)要素の配列\(a\)が与えられる.
- 各クエリでは、\([L, R)\)に含まれる数列\(a\)のdistinctな要素数を答える.
- 配列への更新があっても解けると思いますが、配列への更新はない簡単な問題を考えます.
制約
- \(1 \leq n \leq 10^5\)
- \(0 \leq a_i < n\)
- \(1 \leq Q \leq 10^5\)
考え方
- \([L, R)\)の要素数から、重複している分を引けば良い.
- 区間を左から見たときに、すでに出てきている要素を引くと考えても良い.
- すでに\(x\)が出てきている: 1つ前の\(x\)が区間に含まれている.
方針
- 各インデックス\(i\)について、\(a_i = a_j, j < i\)となる最大の\(j\)を\(p_i\)とする.
- 区間内に\(p_i\)がすでに出てきた: \(L \leq p_i\)である、なので\([L, R)\)に含まれる区間\([p_i, i]\)の個数を\([L, R)\)の要素数から引けば良い.
- 区間に含まれる区間の個数は2次元のセグメント木を用いると各クエリ\(O(log^2(N))\)で計算できるので各クエリ\(O(log^2(N))\)で種類数が分かる.
- 2次元セグメント木において、全要素を陽に持つとMLEするので、クエリで必要なところだけ持つようにした方が良い.
類題
区間\([L, R)\)に対して、各要素\(k\)個まで数える.
- \(p_i\)の定義を、"\(a_i = a_j, j < i\)となる\(k\)番目の\(j\)“に変更すれば良いです.
参考
必要な部分のみ作るセグメント木の例