一、内容

题意:给定一个序列,和许多区间,查询不同区间内不同数的个数。

二、思路

  • 用pre数组记录和当前元素值相同的一个元素的位置,若前面没有则为0。
  • 将询问离线保存在node数组里面,按照区间r小的排在前面。查询时,用一now记录更新到的位置,每次更新到这次查询的r处,若前面有相同的元素,把前面位置-1,当前位置+1,这样就只保存了一次。

三、代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map> 
using namespace std;
const int maxn = 30005;
const int maxq = 2e5 + 5;
struct N{
	int l, r, id;
}node[maxq];
bool cmp(N a, N b) {
	if (a.r == b.r) return a.l < b.l;
	return a.r < b.r;
} 

//pre表示当前位置的元素 前面是否有相同的元素 有就代表下标,无就是0 
int sum[maxn], a[maxn], pre[maxn], n, q, ans[maxq];
void update(int x, int v) {
	for (int i = x; i <= n; i += i & (-i)) {
		sum[i] += v;
	}
}
int query(int x) {
	int ans = 0;
	for (int i = x; i > 0; i -= i & (-i)) {
		ans += sum[i];
	}
	return ans;
}

int main() {
	scanf("%d", &n);
	map<int, int> mp; 
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
		pre[i] = mp[a[i]];
		mp[a[i]] = i; 
	} 
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d", &node[i].l, &node[i].r);
		node[i].id = i;
	}
	sort(node + 1, node + 1 + q, cmp);
	int now = 1;
	for (int i = 1; i <= q; i++) {
		while (now <= node[i].r) {
			if (pre[now]) {
				//删除此位置之前相同的数 
				update(pre[now], -1);
			}
			//将此位置的数 + 1 
			update(now, 1);
			now++; 
		}
		ans[node[i].id] = query(node[i].r) - query(node[i].l - 1);
	}
	for (int i = 1; i <= q; i++) {
		printf("%d\n", ans[i]);
	}
	return 0;
}