Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, ..., aj.
Input
- Line 1: n (1 ≤ n ≤ 30000).
- Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
- Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
- In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).
Output
- For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line.
Example
Input 5 1 1 2 1 3 3 1 5 2 4 3 5 Output 3 2 3
/* 求区间内不重复的数的个数。 扫描数列建立可持久化线段树,第i个数若第一次出现,则在线段树中的位置i加1; 若不是第一次出现,将上次出现的位置减1,在本次位置加1。 对于每个询问的区间 [L,R],在第R个版本上的线段树只有前R个数,在线段树上查询位置L, 对经过的区间中的和进行累计即可*/ #include<stdio.h> #include<map> #define M 1000000 #define N 35000 using namespace std; map<int ,int >ma; int n,num,c[M],lson[M],rson[M],a[N],t[N]; int build(int x,int y) { int root=num++; c[root]=0; if(x!=y) { int mid=(x+y)>>1; lson[root]=build(x,mid); rson[root]=build(mid+1,y); } return root; } int insert(int root,int k,int val) { int newroot,tp,l,r; newroot=num++; tp=num-1; c[newroot]=c[root]+val; l=1;r=n; while(l<r) { int mid=(l+r)>>1; if(k<=mid) { lson[newroot]=num++; rson[newroot]=rson[root]; newroot=lson[newroot]; root=lson[root]; r=mid; } else { rson[newroot]=num++; lson[newroot]=lson[root]; newroot=rson[newroot]; root=rson[root]; l=mid+1; } c[newroot]=c[root]+val; } return tp; } int query(int x,int y,int root,int k) { int mid=(x+y)>>1; if(x==y) return c[root]; if(k<=mid) return c[rson[root]]+query(x,mid,lson[root],k); else return query(mid+1,y,rson[root],k); } int main() { int i,m,x,y,tmp; //freopen("a.txt","r",stdin); while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); num=0; t[0]=build(1,n); ma.clear(); for(i=1;i<=n;i++) { if(ma.find(a[i])==ma.end()) t[i]=insert(t[i-1],i,1); else { tmp=insert(t[i-1],ma[a[i]],-1); t[i]=insert(tmp,i,1); } ma[a[i]]=i; } for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); printf("%d\n",query(1,n,t[y],x)); } } return 0; }
树状数组做法:/*做法:将查询按右端点从小到大排序。从左到右扫,如果该数之前出现过, 则将之前出现过的位置相应删除;当前位置则添加1。这样做就保证每次扫描 到的某一位置,以该位置为右端点的区间都相应地确定了。*/ #include<stdio.h> #include<algorithm> #include<string.h> #include<map> #define N 35000 #define M 250000 using namespace std; struct node { int x,y,id; }b[M]; int c[N],ans[M],a[N]; map<int ,int >ma; bool cmp(node a,node b) { return a.y<b.y; } int lowbit(int x) { return x&(-x); } void update(int x,int val) { while(x<=N) { c[x]+=val; x+=lowbit(x); } } int sum(int x) { int s=0; while(x) { s+=c[x]; x-=lowbit(x); } return s; } int main() { int n,i,m,pre,j; //freopen("a.txt","r",stdin); while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(i=0;i<m;i++) { scanf("%d%d",&b[i].x,&b[i].y); b[i].id=i; } sort(b,b+m,cmp); pre=1; memset(c,0,sizeof(c)); for(i=0;i<m;i++) { for(j=pre;j<=b[i].y;j++) { if(ma.find(a[j])==ma.end()) update(j,1); else { update(ma[a[j]],-1); update(j,1); } ma[a[j]]=j; } ans[b[i].id]=sum(b[i].y)-sum(b[i].x-1); pre=b[i].y+1; } for(i=0;i<m;i++) printf("%d\n",ans[i]); } return 0; }