题意:
给定一个含有n个数的序列,有q个询问,每次询问区间[l,r]中不同数的个数。
思路:
从左向右一个一个将该数字处在的位置添加到主席树中
如果该数字前面未出现过,则在此版本的线段树中的该条链加1,如果该数字已经出现过了,则在此版本线段树的上次出现位置减1,再在此版本线段树的该位置加1,这样就能保证区间不重复计算。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=30005;
struct node{
int l,r,sum;
}T[maxn*40];
int n,q,a[maxn],cnt,root[maxn],pos[1000005];
void update(int &now,int pre,int val,int l,int r,int pos){
T[++cnt]=T[pre],T[cnt].sum+=val,now=cnt;
if(l==r) return;
int mid=l+r>>1;
if(pos<=mid) update(T[now].l,T[pre].l,val,l,mid,pos);
else update(T[now].r,T[pre].r,val,mid+1,r,pos);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return T[rt].sum;
int ans=0,mid=l+r>>1;
if(L<=mid) ans+=query(L,R,l,mid,T[rt].l);
if(R>mid) ans+=query(L,R,mid+1,r,T[rt].r);
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
if(pos[a[i]]){
update(root[i],root[i-1],-1,1,n,pos[a[i]]);
update(root[i],root[i],1,1,n,i);
}else update(root[i],root[i-1],1,1,n,i);
pos[a[i]]=i;
}
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r,1,n,root[r]));
}
return 0;
}