1.思路
扫描数组,以root[i]为根的线段树上记录的是从第一个位置到i位置的数字信息,即当前线段树上的节点记录的是数组的位置信息;
2.code
1 #include <cstdio> 2 #include <map> 3 using namespace std; 4 const int N = 3e4 + 5; 5 6 struct segTree { 7 int lc, rc, cnt; 8 }; 9 10 segTree ret[N*20]; 11 int root[N]; 12 int o; 13 14 void build(int &i, int l, int r) { 15 ret[o].cnt = 0; 16 i = o ++; 17 if(l < r) { 18 int m = (l + r) >> 1; 19 build(ret[i].lc, l, m); 20 build(ret[i].rc, m+1, r); 21 } 22 } 23 24 int query(int rt, int pos, int k, int l, int r) { 25 if(l == r) { 26 return k + ret[rt].cnt; //注意要加上前为值储存的数字的个数 27 } 28 int m = (l + r) >> 1; 29 if(pos <= m) { 30 //向右子树中统计,因为时统计pos之后数字的个数,所以要加上右子树所包含的数字的个数 31 return query(ret[rt].lc, pos, k+ret[ret[rt].rc].cnt, l, m); 32 } 33 else { 34 return query(ret[rt].rc, pos, k, m+1, r); 35 } 36 } 37 38 void update(int &i, int pos, int val, int l, int r) { 39 ret[o] = ret[i]; 40 ret[o].cnt += val; 41 i = o++; 42 if(l < r) { 43 int m = (l + r) >> 1; 44 if(pos <= m) { 45 update(ret[i].lc, pos, val, l, m); 46 } 47 else { 48 update(ret[i].rc, pos, val, m+1, r); 49 } 50 } 51 } 52 53 int main(int argc, char const *argv[]) { 54 int n, m; 55 while(~scanf("%d", &n)) { 56 o = 0; 57 build(root[0], 1, n); 58 map<int, int> mp; 59 int x; 60 for(int i = 1; i <= n; ++ i) { 61 scanf("%d", &x); 62 if(mp.count(x) == 0) { 63 update(root[i] = root[i-1], i, 1, 1, n); // 64 } 65 else { 66 // 将先前一次出现的x的信息删除 67 update(root[i] = root[i-1], mp[x], -1, 1, n); 68 update(root[i], i, 1, 1, n); 69 } 70 mp[x] = i; // 更新最近一次出现x的位置 71 } 72 scanf("%d", &x); 73 while(x --) { 74 int l, r; 75 scanf("%d%d", &l, &r); 76 // 统计以r为根节点的树中l之后的数字个数 77 printf("%d ", query(root[r], l, 0, 1, n)); 78 } 79 } 80 return 0; 81 }