M行,每行一个整数,依次表示询问对应的答案。
HINT
题意:m次查询,每次询问区间[l r]中不同数的个数。
题解:对于区间中不同数的个数,两种做法,在线的话主席树搞搞吧(回头学一发Orz),这里采用离线的做法,
首先我们可以预处理出每个数上一次出现的位置,进而可以思考这样一个问题,对于一个区间中的数,在该区间左边出现的个数即为该区间中数的个数,想想便知,因此我们可以处理出前缀和来解决这个问题,对于一个数,我们可以在该数上一次出现的位置后面一个位置处+1,在当前位置后的位置处-1,利用一发前缀和便能在O(1)的情况下求出答案,然而此时是一个区间询问,首先我们就要想办法让区间变成线性的,这里采用按右端点排序(当然,左端点也可以,不过就是另一种预处理罢了),从左到右枚举右端点,然后更新区间的值(树状数组搞一发),之后根据处理出的前缀和来线性求值即可。
#include<map> #include<stack> #include<queue> #include<vector> #include<math.h> #include<time.h> #include<stdio.h> #include<iostream> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; typedef long long ll; #define inf 2147483647 #define mod 998244353 #define maxn 1000005 #define lowbit(x) (x&-x) #define eps 1e-6 int c[maxn],n,m,p[maxn],pos[maxn],b[maxn],ans[maxn]; struct node { int l,r,id; }a[maxn]; bool comp(node a,node b) { if(a.r==b.r) return a.l<b.l; return a.r<b.r; } void update(int k,int x) { while(k<=n) { c[k]+=x; k+=lowbit(k); } } int getsum(int x) { int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } int main(void) { int i,j,num=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&b[i]); p[i]=pos[b[i]]; pos[b[i]]=i; } scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d",&a[i].l,&a[i].r); a[i].id=i; } sort(a+1,a+m+1,comp); for(i=1;i<=m;i++) { while(num<a[i].r) { num++; update(p[num]+1,1); if(num<n) update(num+1,-1); } ans[a[i].id]=getsum(a[i].l); } for(i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }