Published on

区间种类数

Authors
  • avatar
    Name
    Vegetog
    Twitter

思路

树状数组 + 离线

例题

P1972 [SDOI2009] HH 的项链

按查询的右端点排序

按右端点升序遍历的时候,对于某种数字把当前右端点前最后出现的那个置为1,其余为0

这样区间和即为种类数

int n;
int a[N + 1], t[N + 1];

void add(int p, int v) {
    for (int i = p; i <= n; i += i & -i) t[i] += v;
}
int sum(int p) {
    int res = 0;
    for (int i = p; i >= 1; i -= i & -i) res += t[i];
    return res;
}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    int q;
    cin >> q;
    vector<pair<pii, int>> query;
    for (int i = 0; i < q; i++) {
        int l, r;
        cin >> l >> r;
        query.push_back({{l, r}, i});
    }
    sort(query.begin(), query.end(), [&](pair<pii, int> x, pair<pii, int> y) {
        return x.first.second < y.first.second;
    });

    vector<int> ans(q);
    int po = 1;
    unordered_map<int, int> vis;
    for (int i = 0; i < q; i++) {
        auto [l, r] = query[i].first;
        for (; po <= r; po++) {
            if (vis.count(a[po])) {
                add(vis[a[po]], -1); // 之前出现过,上次出现过的置0
            }
            vis[a[po]] = po;
            add(po, 1);
        }
        ans[query[i].second] = sum(r) - sum(l - 1);
    }
    for (auto x : ans) cout << x << "\n";
}