SPOJ DQUERY D-query (在线主席树/ 离线树状数组)

SPOJ DQUERY

题意:

  给出一串数,询问[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
",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
",ans[i]);
75 
76     return 0;
77 }
原文地址:https://www.cnblogs.com/without-ACM/p/5933341.html