题意 :
n个数,q次查询,每次查询 l 到 r 的区间内不相同的数有多少个。
idea:
主席数维护每个叶子节点有几个数出现过。
#include<bits/stdc++.h>
using namespace std;
const int maxn=30010;
struct node{
int l,r;
int v;
}T[maxn*40];
int cnt=0;
int a[maxn],past[1000100],root[maxn];
void update(int pos,int l,int r,int &cur,int pre,int val){
cur=++cnt;
T[cur]=T[pre];
T[cur].v+=val;
if(l==r)return;
int mid=l+r>>1;
if(pos<=mid)
update(pos,l,mid,T[cur].l,T[pre].l,val);
else
update(pos,mid+1,r,T[cur].r,T[pre].r,val);
}
/*每一颗线段树维护的是一种数在第几个位置出现,及每个叶子节点维护的是,在这个节点有几个数出现过,
即区间和就是这个区间内有几种树*/
int query(int L,int R,int l,int r,int rt){
// cout<<"asd"<<endl;
if(L==l&&r==R)
return T[rt].v;
int mid=l+r>>1;
if(R<=mid)
return query(L,R,l,mid,T[rt].l);
else if(L>=mid+1)
return query(L,R,mid+1,r,T[rt].r);
else
return (query(L,mid,l,mid,T[rt].l)+query(mid+1,R,mid+1,r,T[rt].r));
}
int main(){
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
if(past[a[i]]){
update(past[a[i]],1,n,root[i],root[i-1],-1);
//将新版本的线段树中,将老版本中曾经出现过的这个数删掉
update(i,1,n,root[i],root[i],1);
//将当前出现的位置在新版本的线段树中加上
/*这样做的原理是,在1-n的区间内,每种数只可能在某一个位置出现一次,只是随着时间的推移,
这个数出现的位置会发生改变,那么我就可以查询在某一时间点,其中一种数在哪个位置出现过。
*/
}
else
update(i,1,n,root[i],root[i-1],1);
past[a[i]]=i;
}
int q;scanf("%d",&q);
while(q--){
int l,r;scanf("%d%d",&l,&r);
printf("%d\n",query(l,r,1,n,root[r]));
// cout<<query(l,r,1,n,root[r])<<endl;
}
return 0;
}