- Published on
区间种类数
- Authors

- Name
- Vegetog
思路
树状数组 + 离线
例题
按查询的右端点排序
按右端点升序遍历的时候,对于某种数字把当前右端点前最后出现的那个置为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";
}