计算机

区间不同元素数

给定一个数组,多次查询一个区间中不同元素的数量。

查询的元素需要去重。

例题

模板题: 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

读完了,有什么想法?

阅读已保存的问答示例,并循着引用回到原文。

查看公开问答示例
— 本文完 — 返回文章列表