划分树虽然可以做,但是代码不好记。
看某人blog学习了主席树的简单操作。
引用某大牛的话来解释一下主席树:
所谓主席树呢,就是对原来的数列[1..n]的每一个前缀[1..i](1≤i≤n)建立一棵线段树,线段树的每一个节点存某个前缀[1..i]中属于区间[L..R]的数一共有多少个(比如根节点是[1..n],一共i个数,sum[root] = i;根节点的左儿子是[1..(L+R)/2],若不大于(L+R)/2的数有x个,那么sum[root.left] = x)。若要查找[i..j]中第k大数时,设某结点x,那么x.sum[j] - x.sum[i - 1]就是[i..j]中在结点x内的数字总数。而对每一个前缀都建一棵树,会MLE,观察到每个[1..i]和[1..i-1]只有一条路是不一样的,那么其他的结点只要用回前一棵树的结点即可,时空复杂度为O(nlogn)。
——具体看代码(有详细注释)
1 #include <cstdio> 2 #include <algorithm> 3 #define lc son[now][0], l, mid 4 #define rc son[now][1], mid + 1, r 5 6 using namespace std; 7 8 const int N = 100000 + 5; 9 10 int T, n, q, tot; 11 int a[N], b[N], son[20 * N][2], sum[20 * N], rt[20 * N]; 12 //主席树第 i 棵树存的是 a[0] - a[i] 的树(前缀和) 13 //主席树一个节点 sum 存的是当前线段所包含的数的个数。。晕。 14 //rt 是每一棵树的根节点编号 15 //a 保存原数组,b 保存排序后的数组 16 17 //注意 & 的使用 18 inline void build(int &now, int l, int r) 19 { 20 now = ++tot; 21 sum[now] = 0; 22 if(l == r) return; 23 int mid = (l + r) >> 1; 24 build(lc); 25 build(rc); 26 } 27 28 inline void update(int &now, int l, int r, int last, int x) 29 { 30 now = ++tot; 31 //继承上个节点的孩子 32 son[now][0] = son[last][0]; 33 son[now][1] = son[last][1]; 34 //继承上一个节点的 sum 并加上当前所加入的数的个数(就是1) 35 sum[now] = sum[last] + 1; 36 if(l == r) return; 37 int mid = (l + r) >> 1; 38 if(x <= mid) update(lc, son[now][0], x); 39 else update(rc, son[now][1], x); 40 } 41 42 //因为每个节点存的是有多少个数在当前区间 43 //求区间 [1,3] 即求 rt[3] - rt[0] 内的数 44 //可通过递归二分解决 45 inline int query(int s, int t, int l, int r, int x) 46 { 47 if(l == r) return l; 48 int mid = (l + r) >> 1, cnt = sum[son[t][0]] - sum[son[s][0]]; 49 if(x <= cnt) return query(son[s][0], son[t][0], l, mid, x); 50 else return query(son[s][1], son[t][1], mid + 1, r, x - cnt); 51 } 52 53 int main() 54 { 55 int i, x, y, z, sz; 56 scanf("%d", &T); 57 while(T--) 58 { 59 scanf("%d %d", &n, &q); 60 for(i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i]; 61 sort(b + 1, b + n + 1); 62 sz = unique(b + 1, b + n + 1) - (b + 1);//求不同的数一共有几个,即区间大小 63 tot = 0; 64 build(rt[0], 1, sz); 65 //用每个元素在 b 中的坐标重置 a 数组(离散化) 66 for(i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + sz + 1, a[i]) - b; 67 for(i = 1; i <= n; i++) update(rt[i], 1, sz, rt[i - 1], a[i]); 68 while(q--) 69 { 70 scanf("%d %d %d", &x, &y, &z); 71 printf("%d\n", b[query(rt[x - 1], rt[y], 1, sz, z)]); 72 } 73 } 74 return 0; 75 }