SPOJ DQUERY D-query (在线主席树/ 离线树状数组)
版权声明:本文为博主原创文章,未经博主允许不得转载。
题意:
给出一串数,询问[L,R]区间中有多少个不同的数 。
解法:
关键是查询到某个右端点时,使其左边出现过的数都记录在它们出现的最右位置置1,其他位置置0,然后直接统计[L,R]的区间和就行了。
在线和离线都可以做 。
话不多说,上代码 。
在线主席树
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include <queue> 7 #include <set> 8 #include <vector> 9 #include <map> 10 #define ll long long 11 12 using namespace std; 13 14 const int N=30000+7; 15 const int M=1000000+7; 16 17 int Ls[N*20],Rs[N*20],sum[N*20],root[N]; 18 int tot=0; 19 20 int pos[M]; 21 int a[N]; 22 int n,q; 23 24 inline void copy(int x,int y){ 25 Ls[x]=Ls[y]; 26 Rs[x]=Rs[y]; 27 sum[x]=sum[y]; 28 } 29 30 inline int bulidtree(int L,int R){ 31 if (L>R) return 0; 32 int k=tot++; 33 sum[k]=0; 34 if (L==R) return k; 35 int mid=(L+R)>>1; 36 Ls[k]=bulidtree(L,mid); 37 Rs[k]=bulidtree(mid+1,R); 38 return k; 39 } 40 41 inline int update(int o,int p,int v,int L,int R){ 42 int k=tot++; 43 copy(k,o); 44 sum[k]+=v; 45 46 if (L==R) return k; 47 48 int mid=(L+R)>>1; 49 if (p<=mid) Ls[k]=update(Ls[k],p,v,L,mid); 50 else Rs[k]=update(Rs[k],p,v,mid+1,R); 51 52 return k; 53 } 54 55 inline int query(int o,int x,int y,int L,int R){ 56 if (L==x && R==y) return sum[o]; 57 int mid=(L+R)>>1; 58 if (y<=mid) return query(Ls[o],x,y,L,mid); 59 else if (x>mid) return query(Rs[o],x,y,mid+1,R); 60 else return query(Ls[o],x,mid,L,mid)+query(Rs[o],mid+1,y,mid+1,R); 61 } 62 63 int main(){ 64 scanf("%d",&n); 65 for (int i=1;i<=n;i++) scanf("%d",a+i); 66 67 root[0]=bulidtree(1,n); 68 69 memset(pos,-1,sizeof(pos)); 70 for (int i=1;i<=n;i++){ 71 root[i]=root[i-1]; 72 if (~pos[a[i]]) 73 root[i]=update(root[i],pos[a[i]],-1,1,n); 74 root[i]=update(root[i],i,1,1,n); 75 pos[a[i]]=i; 76 } 77 78 scanf("%d",&q); 79 int x,y; 80 while (q--){ 81 scanf("%d %d",&x, &y); 82 printf("%d\n",query(root[y],x,y,1,n)); 83 } 84 85 return 0; 86 }
离线树状数组
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include <queue> 7 #include <set> 8 #include <vector> 9 #include <map> 10 #define ll long long 11 12 using namespace std; 13 14 const int N=30007; 15 const int Q=200007; 16 const int M=1000007; 17 18 struct query{ 19 int L,R; 20 int id; 21 bool operator < (const query & t) const { 22 return R<t.R; 23 } 24 }q[Q]; 25 26 int a[N]; 27 int pos[M]={}; 28 int ans[Q]; 29 30 int c[N]; // 树状数组 31 int n; 32 33 inline int lowbit(int x){ 34 return x&(-x); 35 } 36 37 inline void add(int x,int d){ 38 while (x<=n) { 39 c[x]+=d; 40 x+=lowbit(x); 41 } 42 } 43 44 inline int sum(int x){ 45 int ret=0; 46 while (x){ 47 ret+=c[x]; 48 x-=lowbit(x); 49 } 50 return ret; 51 } 52 53 int main(){ 54 scanf("%d",&n); 55 for (int i=1;i<=n;i++) scanf("%d",a+i); 56 57 int m; 58 scanf("%d",&m); 59 for (int i=1;i<=m;i++) scanf("%d %d",&q[i].L, &q[i].R),q[i].id=i; 60 sort(q+1,q+1+m); 61 62 int j=1; 63 for (int i=1;i<=n;i++){ 64 if (pos[a[i]]) add(pos[a[i]],-1); 65 add(i,1); 66 pos[a[i]]=i; 67 68 while (j<=m && q[j].R==i){ 69 ans[q[j].id]=sum(q[j].R)-sum(q[j].L-1); 70 j++; 71 } 72 } 73 74 for (int i=1;i<=m;i++) printf("%d\n",ans[i]); 75 76 return 0; 77 }