NC20325 [SDOI2009]HH的项链

发布时间 2023-05-04 11:38:46作者: 空白菌

题目链接

题目

题目描述

HH有一串由各种漂亮的贝壳组成的项链。

HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一 段贝壳,思考它们所表达的含义。

HH不断地收集新的贝壳,因此他的项链变得越来越长。

有一天,他突然提出了一 个问题:某一段贝壳中,包含了多少种不同的贝壳?

这个问题很难回答。。。因为项链实在是太长了。于是,他只 好求助睿智的你,来解决这个问题。

输入描述

第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

输出描述

M行,每行一个整数,依次表示询问对应的答案。

示例1

输入

6
1 2 3 4 3 5
3
1 2 
3 5
2 6

输出

2
2
4

备注

对于20%的数据,\(1\le n,m\leq 5000\)
对于40%的数据,\(1\le n,m\leq 10^5\)
对于60%的数据,\(1\le n,m\leq 5\times 10^5\)
对于100%的数据,\(1\le n,m,a_i \leq 10^6,1\le l \le r \le n\)

本题可能需要较快的读入方式,最大数据点读入数据约 20MB

题解

知识点:树状数组,离线,枚举。

首先需要一个事实,同种颜色我们只需要其出现一次即可,出现多次是不利于计算。

通过这个事实,我们考虑从左到右枚举,记录每个颜色最新一次出现的位置,撤销掉上一次的位置,随后将询问离线按右端点从小到大排序后询问即可。

还有一种朴素莫队的做法,复杂度是 \(O(n\sqrt m)\) ,很可惜过不了全部数据点。

时间复杂度 \(O((n+m) \log n + m\log m)\)

空间复杂度 \(O(n + m)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template<class T>
class Fenwick {
    int n;
    vector<T> node;

public:
    Fenwick(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n + 1, T());
    }

    void update(int x, T val) { for (int i = x;i <= n;i += i & -i) node[i] += val; }

    T query(int x) {
        T ans = T();
        for (int i = x;i;i -= i & -i) ans += node[i];
        return ans;
    }
    T query(int x, int y) {
        T ans = T();
        ans += query(y);
        ans -= query(x - 1);
        return ans;
    }
};

struct T {
    int sum = 0;
    T &operator+=(const T &x) { return sum += x.sum, *this; }
    T &operator-=(const T &x) { return sum -= x.sum, *this; }
};

int a[1000007];

struct Query {
    int l, r, id;
}q[1000007];

int pos[1000007];
int ans[1000007];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> a[i];
    int m;
    cin >> m;
    for (int i = 1;i <= m;i++) {
        int l, r;
        cin >> l >> r;
        q[i] = { l,r,i };
    }
    sort(q + 1, q + m + 1, [&](auto a, auto b) {return a.r < b.r;});

    Fenwick<T> fw(n);
    int cur = 1;
    for (int i = 1;i <= m;i++) {
        while (cur <= q[i].r) {
            if (pos[a[cur]]) fw.update(pos[a[cur]], { -1 });
            fw.update(cur, { 1 });
            pos[a[cur]] = cur;
            cur++;
        }
        ans[q[i].id] = fw.query(q[i].l, q[i].r).sum;
    }

    for (int i = 1;i <= m;i++) cout << ans[i] << '\n';
    return 0;
}