题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式
第一行:一个整数N,表示项链的长度。

第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。

第三行:一个整数M,表示HH 询问的个数。

接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

输出格式
M 行,每行一个整数,依次表示询问对应的答案。

输入输出样例
输入 #1 复制

6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出 #1 复制
2
2
4
说明/提示
对于20%的数据,n,m\leq 5000n,m≤5000

对于40%的数据,n,m\leq 10^5n,m≤10
5

对于60%的数据,n,m\leq 5\times 10^5n,m≤5×10
5

对于所有数据,n,m\leq 1\times 10^6n,m≤1×10
6

本题可能需要较快的读入方式,最大数据点读入数据约20MB


查四六级好慌,写个博客压压惊。

简单的离线+树状数组(或者线段树)


我们可以对查询按照右端点排序,然后我们就只需要记录每个数字右边出现的第一次就可以了。然后统计答案就行了。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
#define lowbit(x) (x&(-x))
using namespace std;
const int N=1e6+10;
int n,m,a[N],d[N],res[N],vis[N];
struct node{
	int l,r,id;
}t[N];
int cmp(const node a,const node b){
	return a.r<b.r;
}
inline void add(int x,int v){
	for(int i=x;i<=n;i+=lowbit(i))	d[i]+=v;
}
inline int ask(int x){
	int res=0;	for(int i=x;i;i-=lowbit(i))	res+=d[i];	return res;
}
signed main(){
	scanf("%d",&n);	for(int i=1;i<=n;i++)	scanf("%d",&a[i]);scanf("%d",&m);
	for(int i=1;i<=m;i++)	scanf("%d %d",&t[i].l,&t[i].r),t[i].id=i;
	sort(t+1,t+1+m,cmp);	int nex=1;
	for(int i=1;i<=m;i++){
		for(int j=nex;j<=t[i].r;j++){
			if(vis[a[j]])	add(vis[a[j]],-1);
			add(j,1);	vis[a[j]]=j;
		}
		nex=t[i].r+1;
		res[t[i].id]=ask(t[i].r)-ask(t[i].l-1);
	}
	for(int i=1;i<=m;i++)	printf("%d\n",res[i]);
	return 0;
}