区间不同元素数
给定一个数组,多次查询一个区间中不同元素的数量。
查询的元素需要去重。
例题
模板题: 2009 山东省选 小 H 的项链
离线查询
将所有的查询按右端点排序,然后使用树状数组记录右端点到 i 时的贡献。
具体的说,以 1 2 3 1 为例,到第二个 1(下标为 4)时,先将第一个 1 的贡献抹去,然后再加入第二个 1。并且,一旦有以该位置为右端点的查询,就动态地处理出该端点。
要抹去上一次贡献,就记录同一个数上次出现是什么时候,使用一个数组 last 记录即可。
代码如下,时间复杂度 O(n \log n)。
struct Query {
size_t i;
size_t l, r;
friend bool operator<(Query u, Query v)
{
return u.r < v.r;
}
} queries[MAXN];
unsigned ans[MAXN];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (size_t i = 1; i <= n; i++)
{
cin >> a[i];
last[i] = old[a[i]];
old[a[i]] = i;
}
size_t m;
cin >> m;
for (size_t i = 1; i <= m; i++)
{
queries[i].i = i;
cin >> queries[i].l >> queries[i].r;
}
sort(queries + 1, queries + m + 1);
for (size_t i = 1, j = 1; i <= n; i++)
{
upd(i, 1);
if (last[i])
{
upd(last[i], -1);
}
while (j <= m && queries[j].r <= i)
{
size_t l = queries[j].l, r = queries[j].r;
ans[queries[j].i] = query(r) - query(l - 1);
j++;
}
}
for (size_t i = 1; i <= m; i++)
{
cout << ans[i] << '\n';
}
return 0;
}
在线查询
BEYOND THE ARTICLE
读完了,有什么想法?
阅读已保存的问答示例,并循着引用回到原文。
— 本文完 — 返回文章列表