spoj DQUERY - D-query (询问区间中不同数的个数,线段树(离线) or 莫队算法(离线) or 主席树(在线))

题目链接 题意:给出n个数,然后m个询问,每个询问一个区间[l,r],问该区间中不同的数有多少个。

思路:离线处理+线段树的做法不多说了:

 1/* ***********************************************
 2Author :111qqz
 3Created Time :Fri 16 Sep 2016 11:34:32 PM CST
 4File Name :code/spoj/dquery.cpp
 5************************************************ */
 6#include <cstdio>
 7#include <cstring>
 8#include <iostream>
 9#include <algorithm>
10#include <vector>
11#include <queue>
12#include <set>
13#include <map>
14#include <string>
15#include <cmath>
16#include <cstdlib>
17#include <ctime>
18#define fst first
19#define sec second
20#define lson l,m,rt<<1
21#define rson m+1,r,rt<<1|1
22#define ms(a,x) memset(a,x,sizeof(a))
23typedef long long LL;
24#define pi pair < int ,int >
25#define MP make_pair
26using namespace std;
27const double eps = 1E-8;
28const int dx4[4]={1,0,0,-1};
29const int dy4[4]={0,-1,1,0};
30const int inf = 0x3f3f3f3f;
31const int N=3E4+7;
32const int M=2E5+7;
33int n,Q;
34int a[N];
35int tree[N<<2];
36map<int,int>mp;
37struct node
38{
39    int l,r;
40    int id;
41    bool operator < (node b)const
42    {
43    if (r==b.r) return l<b.l;
44    return r<b.r;
45    }
46}q[M];
47void PushUp( int rt)
48{
49    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
50}
51void update( int p,int sc,int l,int r ,int rt)
52{
53    if (l==r)
54    {
55    tree[rt]+=sc;
56    return;
57    }
58    int m = (l+r)>>1;
59    if (p<=m) update(p,sc,lson);
60    else update(p,sc,rson);
61    PushUp(rt);
62}
63int query(int L,int R,int l,int r,int rt)
64{
65    if (L<=l&&r<=R) return tree[rt];
66    int m = (l+r)>>1;
67    int ret = 0 ;
68    if (L<=m)  ret += query(L,R,lson);
69    if (R>=m+1) ret+=query(L,R,rson);
70    return ret;
71}
72int ans[M];
73int main()
74{
75    #ifndef  ONLINE_JUDGE 
76    freopen("code/in.txt","r",stdin);
77  #endif
78    cin>>n;
79    for ( int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
80    cin>>Q;
81    for ( int i = 1 ; i <= Q ; i++) scanf("%d %d",&q[i].l,&q[i].r),q[i].id = i ;
82    sort(q+1,q+Q+1);
83    int cur = 1;
84    for ( int i = 1 ; i <= Q ; i++)
85    {
86        for ( ; cur <= q[i].r ; cur++)
87        {
88        if (mp[a[cur]]) update(mp[a[cur]],-1,1,n,1);
89        mp[a[cur]] = cur;
90        update(mp[a[cur]],1,1,n,1);
91        }
92        ans[q[i].id] = query(q[i].l,q[i].r,1,n,1);
93    }
94    for ( int i = 1 ; i <= Q ; i++) printf("%d\n",ans[i]);
95  #ifndef ONLINE_JUDGE  
96  fclose(stdin);
97  #endif
98    return 0;
99}

之后补一个主席树的做法

先来补一个莫队的做法。

因为a[i]<=1E6,可以很方便得统计每个数出现的次数,update的时候,如果是1变成0,那么区间中不同的数的个数减1,如果是0变成1,那么区间中不同数个数+1

  1/* ***********************************************
  2Author :111qqz
  3Created Time :Fri 16 Sep 2016 11:34:32 PM CST
  4File Name :code/spoj/dquery.cpp
  5************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int MAXN = 1E6+7;
 34const int N=3E4+7;
 35const int M=2E5+7;
 36int n,Q;
 37int a[N];
 38int pos[N];
 39int sum;
 40int cnt[MAXN]={0};
 41struct node
 42{
 43    int l,r;
 44    int id;
 45    bool operator < (node b)const
 46    {
 47    if (pos[l]==pos[b.l]) return r<b.r;
 48    return pos[l] < pos[b.l];
 49    }
 50}q[M];
 51
 52int ans[M];
 53void update ( int x,int d)
 54{
 55    cnt[a[x]]+=d;
 56    if (d==1&&cnt[a[x]]==1) sum++;
 57    if (d==-1&&cnt[a[x]]==0) sum--;
 58}
 59
 60int main()
 61{
 62    #ifndef  ONLINE_JUDGE 
 63    freopen("./in.txt","r",stdin);
 64  #endif
 65    int bk = 173;// sqrt(30000)
 66    cin>>n;
 67    for ( int i = 1 ; i <= n ; i++) 
 68    {
 69        scanf("%d",&a[i]);
 70        pos[i] = (i-1)/bk;
 71    }
 72    cin>>Q;
 73    for ( int i = 1 ; i <= Q ; i++) scanf("%d %d",&q[i].l,&q[i].r),q[i].id = i ;
 74    sort(q+1,q+Q+1);
 75    int pl=1,pr=0,id,l,r;
 76    ms(cnt,0);
 77    sum = 0 ;
 78    for ( int i = 1 ; i <= Q ; i++)
 79    {
 80        id = q[i].id;
 81        l = q[i].l;
 82        r = q[i].r;
 83        if (pr<r)
 84        {
 85        for ( int j = pr+1 ; j <= r ; j++)
 86            update(j,1);
 87        }
 88        else 
 89        {
 90        for ( int j = r+1 ; j <= pr ; j++)
 91            update(j,-1);
 92        }
 93        pr = r;
 94        if (pl<l)
 95        {
 96        for ( int j = pl ; j <= l-1 ; j++)
 97            update(j,-1);
 98        }
 99        else
100        {
101        for ( int j = l ; j <= pl-1 ; j++)
102            update(j,1);
103        }
104        pl = l;
105        ans[id] = sum;
106    }
107    for ( int i = 1 ; i <= Q ; i++) printf("%d\n",ans[i]);
108
109
110  #ifndef ONLINE_JUDGE  
111  fclose(stdin);
112  #endif
113    return 0;
114}

补一个在线的做法,可持久化线段树,其实思路和离线线段树几乎一样。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :Fri 16 Sep 2016 11:34:32 PM CST
  4File Name :code/spoj/dquery.cpp
  5************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int N=3E4+7;
 34const int M=2E5+7;
 35int n,Q;
 36int a[N],root[N];
 37map<int,int>mp;
 38int cnt;
 39struct Ptree
 40{
 41    int sum;
 42    int left,right;
 43}tree[N*30];
 44void build (int &rt,int l,int r)
 45{
 46    rt =++cnt;
 47    tree[rt].sum = 0 ;
 48    if (l==r) return;
 49    int mid = (l+r)>>1;
 50    build (tree[rt].left,l,mid);
 51    build (tree[rt].right,mid+1,r);
 52}
 53inline int add_node(int _sum,int _left,int _right)
 54{
 55    int idx = ++cnt;
 56    tree[idx].sum = _sum;
 57    tree[idx].left = _left;
 58    tree[idx].right = _right;
 59    return idx;
 60}
 61void Insert(int &root,int pre_rt,int pos,int val,int l,int r)
 62{
 63//    printf("l:%d r:%d\n",l,r);
 64    root = add_node(tree[pre_rt].sum + val,tree[pre_rt].left,tree[pre_rt].right);
 65   // root = ++cnt;
 66   // tree[root].sum = tree[pre_rt].sum+ val;
 67   // tree[root].left = tree[pre_rt].left;
 68   // tree[root].right = tree[pre_rt].right;
 69    if (l==r) return;
 70    int mid = (l+r)>>1;
 71    if (pos<=mid) Insert(tree[root].left,tree[pre_rt].left,pos,val,l,mid);
 72    else Insert(tree[root].right,tree[pre_rt].right,pos,val,mid+1,r);
 73}
 74int query(int pos,int l,int r,int rt)
 75{
 76    if (l==r) return tree[rt].sum;
 77    int mid = (l+r)>>1;
 78    if (pos<=mid) return query(pos,l,mid,tree[rt].left);
 79    else return tree[tree[rt].left].sum + query(pos,mid+1,r,tree[rt].right);
 80}
 81int main()
 82{
 83    #ifndef  ONLINE_JUDGE 
 84    freopen("./in.txt","r",stdin);
 85  #endif
 86    ms(tree,0);
 87    cnt = 0 ;
 88    cin>>n;
 89    for ( int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
 90    build (root[n+1],1,n);
 91    mp.clear();
 92    for ( int i = n ; i >= 1 ; i--)
 93    {
 94        if (mp.find(a[i])==mp.end())
 95        {
 96        Insert(root[i],root[i+1],i,1,1,n);
 97        }
 98        else
 99        {
100        Insert(root[i],root[i+1],mp[a[i]],-1,1,n);
101        Insert(root[i],root[i],i,1,1,n);
102        }
103        mp[a[i]] = i;
104    }
105    cin>>Q;
106    while (Q--)
107    {
108        int l,r;
109        scanf("%d %d",&l,&r);
110       // printf("l:%d r:%d\n",l,r);
111        int ans = query(r,1,n,root[l]);
112        printf("%d\n",ans);
113    }
114  #ifndef ONLINE_JUDGE  
115  fclose(stdin);
116  #endif
117    return 0;
118}