题意:
给定一个长度为 n n n的序列 a a a, m m m次询问,每次询问区间 [ l , r ] [l,r] [l,r]内不同数的个数。
数据范围: 1 ≤ n ≤ 30000 , 1 ≤ a i ≤ 1 0 6 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ l ≤ r ≤ n 1\leq n\leq 30000, 1\leq a_i\leq 10^6, 1\leq m\leq 2\times 10^5, 1\leq l\leq r\leq n 1≤n≤30000,1≤ai≤106,1≤m≤2×105,1≤l≤r≤n
题解:
a i a_i ai不大可以直接使用标记数组。
枚举当前区间左端点为 1 1 1,右端点为 r r r,则我们记录 [ 1 , r ] [1,r] [1,r]中所有数最后一次出现的位置,这样可以求出所有 [ l , r ] [l,r] [l,r]中不同数的个数, 1 ≤ l ≤ r 1\leq l\leq r 1≤l≤r。所以我们将询问存储下来然后按右端点排序依次按照右端点进行标记数组的更新即可。
如 [ 1 , 2 , 3 , 1 , 2 ] [1,2,3,1,2] [1,2,3,1,2]的标记数组:
当 r = 3 r=3 r=3: [ 1 , 1 , 1 ] [1,1,1] [1,1,1] 可以求出: [ 1 , 3 ] , [ 2 , 3 ] , [ 3 , 3 ] [1,3],[2,3],[3,3] [1,3],[2,3],[3,3]
当 r = 4 r=4 r=4: [ 0 , 1 , 1 , 1 ] [0,1,1,1] [0,1,1,1] 可以求出: [ 1 , 4 ] , [ 2 , 4 ] , [ 3 , 4 ] , [ 4 , 4 ] [1,4],[2,4],[3,4],[4,4] [1,4],[2,4],[3,4],[4,4]
当 r = 5 r=5 r=5: [ 0 , 0 , 1 , 1 , 1 ] [0,0,1,1,1] [0,0,1,1,1] 可以求出: [ 1 , 5 ] , [ 2 , 5 ] , [ 3 , 5 ] , [ 4 , 5 ] , [ 5 , 5 ] [1,5],[2,5],[3,5],[4,5],[5,5] [1,5],[2,5],[3,5],[4,5],[5,5]
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N], b[N];
int ans[N];
int tr[N];
map<int, int> mp;
int n, dn, m;
struct Node {
int l, r, id;
}q[N];
bool cmpA(Node A, Node B) {
if(A.r == B.r) return A.l < B.l;
return A.r < B.r;
}
bool cmpB(Node A, Node B) {
return A.id < B.id;
}
void add(int p, int x) {
for(int i = p; i <= n; i += (i & -i)) tr[i] += x;
}
int sum(int p) {
int res = 0;
for(int i = p; i >= 1; i -= (i & -i)) res += tr[i];
return res;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]), b[i] = a[i];
scanf("%d", &m);
for(int i = 1; i <= m; ++i)
scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q + m + 1, cmpA);
int r = 1;
for(int i = 1; i <= m; ++i) {
while(r <= q[i].r) {
if(mp.count(a[r])) {
add(mp[a[r]], -1);
}
mp[a[r]] = r;
add(r, 1);
++r;
}
int j = i;
while(j <= m && q[j].r == q[i].r) {
ans[q[j].id] = sum(q[j].r) - sum(q[j].l - 1);
++j;
}
i = j - 1;
}
sort(q + 1, q + m + 1, cmpB);
for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}