T815912
我们先要吧公式搞好。
for (int i = 1; i <= n; i++) {
// 若 a[i] 之前出现过,撤销旧的贡献
if (last[a[i]])
update(1, 1, n, llast[a[i]] + 1, last[a[i]], 1);
// 注意:这里参数是 1,配合下面的"查询"逻辑理解
// 通常这里的实现是:在 [llast+1, last] 区间 -1,
// 但代码用了 +1 并配合前缀/后缀查询方式,
// 具体取决于 update/query 的定义
// 更新出现位置
llast[a[i]] = last[a[i]];
last[a[i]] = i;
// 处理所有右端点为 i 的查询
for (int x : qrt[i])
ans[x] = query(1, 1, n, ql[x]);
}
-
当遍历到位置 \(i\),值为 \(v = a_i\):
若 \(v\) 之前出现过(
last[v] != 0),说明原来在 \(last_v\) 处的"贡献 \(1\)"要撤销,改到 \(i\) 处贡献。撤销方式:在区间 \(llast_v + 1 \sim last_v\) 上加 \(-1\)(因为只有左端点落在这个区间内的查询,才会包含 \(last_v\) 这个位置而不包含 \(i\))。
然后在位置 \(i\) 加 \(1\)。

浙公网安备 33010602011771号