[SDOI2009]HH的项链
Link
题目描述
有一个序列,每次询问区间内有多少不同元素,元素值小于 \(1e6\)。
解法
考虑到每个元素都只有在区间内和不在区间内两种状态,而没有修改操作,考虑离线询问。用 \(flag[a[j]]\) 表示 \(a[j]\) 这个元素的最后一次的出现位置。遇到一个新的元素,若 \(flag[a[j]]\) 有值,则把这个位置在树状数组里的值删去,并加上新的这个 \(a[j]\) 的位置。这样同种元素只会被记录一次,再用树状数组维护前缀和,最后做差就是答案。
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 1000007
struct Pos{
int l,r;
int pos;
}node[N>>1];
int tr[N],ans[N],flag[N];
int a[N>>1],n,m;
inline void read(int &x){
x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
}
inline bool cmp(Pos x,Pos y){
return x.r<y.r;
}
inline int lowbit(int x){return (-x)&x;}
inline void update(int u,int val){
while(u<=n){
tr[u]+=val;
u+=lowbit(u);
}
}
inline int query(int u){
int rest=0;
while(u>0){
rest+=tr[u];
u-=lowbit(u);
}
return rest;
}
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
read(m);
for(int i=1;i<=m;i++) read(node[i].l),read(node[i].r),node[i].pos=i;
sort(node+1,node+1+m,cmp);
int next=1;
for(int i=1;i<=m;i++){
for(int j=next;j<=node[i].r;j++){
if(flag[a[j]]) update(flag[a[j]],-1);
update(j,1);
flag[a[j]]=j;
}
next=node[i].r+1;
ans[node[i].pos]=query(node[i].r)-query(node[i].l-1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}