题意:查找区间内不同数字的个数。
两种做法,一种是 树状数组离线,另一种就是主席树。
树状数组离线操作的链接 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\n",query(per_root[r],l)); 104 } 105 } 106 return 0; 107 }
时间: 2024-10-09 04:01:39