SPOJ D-query
主席树求区间不同数字个数模板题。
求不同个数就是把数组下标建一颗主席树,如果当前数字已经在前面出现过,那么在当前线段树里把之前出现的区间-1,然后把现在出现的区间+1。
-1是因为当前点和重复数字出现的区间所组成的区间答案要减1,+1相当于现在出现了一个新的数字。
查询的时候查询第R颗线段树的出现L区间的不同数字和即可。
#include <bits/stdc++.h> using namespace std; const int M = 3e4+7; int n,q,a[M],tot,pos; int num[M<<5],L[M<<5],R[M<<5],T[M],flag[1000007]; /*************************zhuxishu***************************/ void build(int l,int r,int &rt){ rt=++tot; num[rt]=0; if(l==r) return ; int mid=(l+r)>>1; build(l,mid,L[rt]); build(mid+1,r,R[rt]); } void update(int l,int r,int &rt,int pre,int v){ rt=++tot; num[rt]=num[pre]+v; if(l==r) return ; int mid=(l+r)>>1; L[rt]=L[pre];R[rt]=R[pre]; if(pos<=mid) update(l,mid,L[rt],L[pre],v); else update(mid+1,r,R[rt],R[pre],v); } int query(int p,int l,int r,int rt){ if(l==r){ return num[rt]; } int mid=(l+r)>>1,res=0; if(p<=mid){ res+=num[R[rt]]; res+=query(p,l,mid,L[rt]); } else{ res+=query(p,mid+1,r,R[rt]); } return res; } /*************************solve**************************/ void solve(){ build(1,n,T[0]);int t; for(int i=1;i<=n;i++){ pos=i; if(flag[a[i]]){ pos=flag[a[i]]; update(1,n,t,T[i-1],-1);pos=i; update(1,n,T[i],t,1); } else update(1,n,T[i],T[i-1],1); flag[a[i]]=i; } scanf("%d",&q); while(q--){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",query(x,1,n,T[y])); } } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d",&n);tot=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); solve(); return 0; }

浙公网安备 33010602011771号