个人理解:
每个新的线段树的一个结点保存的是1...位置 i中的数字在相应的区间上有几个。
然后我们用r-(l-1)得到的就是l...r上的中字在相应的区间中出现了几个。
题目1 POJ2104
题目大意:静态查询区间第K小值。
裸的可持久化线段树。
1 #include <cstdlib> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 7 using namespace std; 8 const int N = 100000 + 5; 9 10 struct SegTree { 11 int l, r, size; 12 }Node[N * 30]; 13 14 struct data { 15 int v, pos; 16 bool operator < (const data &k) const { 17 return v < k.v; 18 } 19 }a[N]; 20 21 int n, m, rank[N], l, r, k, root[N], tot; 22 23 void build(int &o, int l, int r) { 24 o = ++ tot; 25 Node[o].l = Node[o].r = Node[o].size = 0; 26 if(l >= r) return; 27 int mid = (l + r) >> 1; 28 build(Node[o].l, l, mid); 29 build(Node[o].r, mid + 1, r); 30 } 31 32 void update(int pre, int &o, int l, int r, int kth) { 33 o = ++ tot; 34 Node[o] = Node[pre]; 35 Node[o].size ++; 36 if(l >= r) return; 37 int mid = (l + r) >> 1; 38 if(kth <= mid) 39 update(Node[pre].l, Node[o].l, l, mid, kth); 40 else 41 update(Node[pre].r, Node[o].r, mid + 1, r, kth); 42 } 43 44 int query(int r1, int r2, int l, int r, int kth) { 45 if(l >= r) return l; 46 int lc = Node[Node[r2].l].size - Node[Node[r1].l].size; 47 int mid = (l + r) >> 1; 48 if(lc >= kth) 49 return query(Node[r1].l, Node[r2].l, l, mid, kth); 50 else 51 return query(Node[r1].r, Node[r2].r, mid + 1, r, kth - lc); 52 } 53 54 int main() { 55 scanf("%d%d", &n, &m); 56 for(int i = 1; i <= n; ++ i) { 57 scanf("%d", &a[i].v); 58 a[i].pos = i; 59 } 60 sort(a + 1, a + n + 1); 61 for(int i = 1; i <= n; ++ i) 62 rank[a[i].pos] = i; 63 build(root[0], 1, n); 64 for(int i = 1; i <= n; ++ i) 65 update(root[i - 1], root[i], 1, n, rank[i]); 66 for(int i = 1; i <= m; ++ i) { 67 scanf("%d%d%d", &l, &r, &k); 68 printf("%d\n", a[query(root[l - 1], root[r], 1, n, k)].v); 69 } 70 return 0; 71 }
2104
时间: 2024-10-09 01:29:35