SPOJ - 3267. D-query 主席树求区间个数
主席树的又一种写法。 从后端点开始添加主席树, 然后如果遇到出现过的元素先把那个点删除, 再更新树, 最后查询区间就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 //#define lson l,m,rt<<1 10 //#define rson m+1,r,rt<<1|1 11 #define max3(a,b,c) max(a,max(b,c)) 12 #define min3(a,b,c) min(a,min(b,c)) 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const LL mod = (int)1e9+7; 16 const int N = 3e4 + 100; 17 const int M = 1e6 + 100; 18 int root[N], lson[M], rson[M], cnt[M]; 19 int a[N]; 20 map<int,int> mp; 21 int tot; 22 int Build(int l, int r){ 23 int now = ++tot; 24 cnt[now] = 0; 25 if(l < r){ 26 int m = l+r >> 1; 27 lson[now] = Build(l, m); 28 rson[now] = Build(m+1, r); 29 } 30 return now; 31 } 32 int Update(int l, int r, int pre, int c, int v){ 33 int now = ++tot; 34 cnt[now] = cnt[pre] + v; 35 if(l < r){ 36 int m = l+r >> 1; 37 if(c <= m){ 38 rson[now] = rson[pre]; 39 lson[now] = Update(l, m, lson[pre], c, v); 40 } 41 else { 42 lson[now] = lson[pre]; 43 rson[now] = Update(m+1, r, rson[pre], c, v); 44 } 45 } 46 return now; 47 } 48 int Query(int l, int r, int p, int R){ 49 if(l == r) return cnt[p]; 50 int m = l+r >> 1; 51 if(R <= m){ 52 return Query(l, m, lson[p], R); 53 } 54 else { 55 return Query(m+1,r,rson[p],R) + cnt[lson[p]]; 56 } 57 } 58 int main(){ 59 int n; 60 scanf("%d", &n); 61 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 62 root[n+1] = Build(1, n); 63 for(int i = n; i >= 1; i--){ 64 if(mp[a[i]] == 0){ 65 root[i] = Update(1, n, root[i+1], i, 1); 66 } 67 else { 68 int tmp = Update(1, n, root[i+1], mp[a[i]], -1); 69 root[i] = Update(1, n, tmp, i, 1); 70 } 71 mp[a[i]] = i; 72 } 73 int m, l, r; 74 scanf("%d", &m); 75 for(int i = 1; i <= m; i++){ 76 scanf("%d%d", &l, &r); 77 printf("%d\n", Query(1,n,root[l],r)); 78 } 79 return 0; 80 81 }