SPOJ3267--D-query (主席树入门练习)

题意:查找区间内不同数字的个数。

两种做法,一种是 树状数组离线,另一种就是主席树。

树状数组离线操作的链接 http://www.cnblogs.com/oneshot/p/4110415.html

两种方法思路差不多,都是扫一遍,如果这个数曾经出现过那么就 在上次位置-1,如果没有出现过就在 当前位置+1,同时更新该数字的最新的位置。

这样的话,在主席树里面 以x为根的线段树存的就是1-x之间不同的数字的个数。我们只需要查找以r为根的线段树同时大于l的区间内的个数就行了。

给主席跪了,orz。主席树其实就是每个位置对应一颗线段树,但是这样 n 个点 n 棵线段树显然会MLE,怎么解决呢?我们可以看到 从第 i 棵线段树到第i+1 棵线段树,很多子树都是相同的,这样如果再重新建一棵完整的线段树显然浪费了很大的空间。我们只需要把第i棵线段树的 某个子树同时第i+1棵线段树 某个 节点下面即可,这样就大大减小了空间复杂度。

  1 #include <map>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <algorithm>
  7 using namespace std;
  8 const int maxn = 3e4+10;
  9 int a[maxn],c[maxn*18],lson[maxn*18],rson[maxn*18],tot,n,m;
 10 int build(int l,int r)
 11 {
 12     int root = tot++;
 13     c[root] = 0;
 14     if (l != r)
 15     {
 16         int mid = (l + r) >> 1;
 17         lson[root] = build(l,mid);
 18         rson[root] = build(mid + 1,r);
 19     }
 20     return root;
 21 }
 22 int update(int root,int pos,int val)
 23 {
 24     int newroot = tot++;
 25     int tmp = newroot;
 26     c[newroot] = c[root] + val;
 27     int l = 1,r = n;
 28     while (l < r)
 29     {
 30         int mid = (l + r) >> 1;
 31         if (pos <= mid)
 32         {
 33             rson[newroot] = rson[root];
 34             lson[newroot] = tot++;
 35             newroot = lson[newroot];
 36             root = lson[root];
 37             r = mid;
 38         }
 39         else
 40         {
 41             lson[newroot] = lson[root];
 42             rson[newroot] = tot++;
 43             newroot = rson[newroot];
 44             root = rson[root];
 45             l = mid + 1;
 46         }
 47         c[newroot] = c[root] + val;
 48     }
 49     return tmp;
 50 }
 51 int query(int root,int pos)
 52 {
 53     int res = 0;
 54     int l = 1,r = n;
 55     while (pos > l)
 56     {
 57         int mid = (l + r) >> 1;
 58         if (pos <= mid)
 59         {
 60             res += c[rson[root]];
 61             root = lson[root];
 62             r = mid;
 63         }
 64         else
 65         {
 66             root = rson[root];
 67             l = mid + 1;
 68         }
 69     }
 70     return res + c[root];
 71 }
 72 int per_root[maxn];
 73 int main(void)
 74 {
 75     #ifndef ONLINE_JUDGE
 76         freopen("in.txt","r",stdin);
 77     #endif
 78     while (~scanf ("%d",&n))
 79     {
 80         tot = 0;
 81         for (int i = 1; i <= n ;i++)
 82             scanf ("%d",a+i);
 83         per_root[0] = build(1,n);
 84         map<int,int>mp;
 85         for (int i = 1; i <= n; i++)
 86         {
 87             if (mp.find(a[i]) == mp.end())
 88             {
 89                 per_root[i] = update(per_root[i-1],i,1);
 90             }
 91             else
 92             {
 93                 int tmp = update(per_root[i-1],mp[a[i]],-1);
 94                 per_root[i] = update(tmp,i,1);
 95             }
 96             mp[a[i]] = i;
 97         }
 98         scanf ("%d",&m);
 99         for (int i = 0; i < m; i++)
100         {
101             int l,r;
102             scanf ("%d%d",&l,&r);
103             printf("%d
",query(per_root[r],l));
104         }
105     }
106     return 0;
107 }
原文地址:https://www.cnblogs.com/oneshot/p/4112825.html