题意
给一个序列,并且给出q个询问,每一个询问查询一个区间内的数的种类数
解法
下标树状数组+离线处理+vector
具体思路
对于每一个询问[l,r],将l记录到右端点所在的vector中,然后遍历右端点。
对于当前遍历到的右端点,此时的右端点所占有的数是a[i],如果前面也有a[i],将前面的a[i]删除,然后将右端点的a[i]插入,**注意
,**插入的是下标i,并不是a[i]
代码
#include<bits/stdc++.h>
#include<array>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 3e6 + 5;
ll n, m;
ll k;
ll a[N];
int t = 1;
vector<pair<int,int>>v[N];
ll c[N];
ll maxn = 5e5 + 5;
void add(int pos,int d) {
while (pos <= maxn) {
c[pos] += d;
pos += pos & -pos;
}
}
ll ask(int pos) {
ll ans = 0;
while (pos) {
ans += c[pos];
pos -= pos & -pos;
}
return ans;
}
ll mark[N];
ll ans[N];
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n>>m;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= m; i++) {
ll l, r;
cin >> l >> r;
v[r].push_back({ l,i });
}
for (int i = 1; i <= n; i++) {
if (mark[a[i]]) {
add(mark[a[i]], -1);//将上一个减去
}
mark[a[i]] = i;
add(i, 1);//插入这一个
for (auto j : v[i]) {
ans[j.second] = ask(i) - ask(j.first-1);
}
}
for (int i = 1; i <= m; i++) {
cout << ans[i] << endl;
}
}