POJ2104-- K-th Number(主席树静态区间第k大)

[转载]一篇还算可以的文章,关于可持久化线段树 http://finaltheory.info/?p=249

无修改的区间第K大

  • 我们先考虑简化的问题:我们要询问整个区间内的第K大。这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值。

  • 现在我们要回答对于区间[l, r]的第K大询问。如果我们能够得到一个插入原序列中[1, l – 1]元素的线段树,和一颗插入了[1, r]元素的线段树,由于线段树是开在值域上,区间长度是一定的,所以结构也必然是完全相同的,我们可以直接对这两颗线段树进行相减,得到的是相当于插入了区间[l ,r]元素的线段树。注意这里利用到的区间相减性质,实际上是用两颗不同历史版本的线段树进行相减:一颗是插入到第l-1个元素的旧树,一颗是插入到第r元素的新树。

下面是代码

  1 #include <cstdio>
  2 #include <string>
  3 #include <vector>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <iostream>
  7 #include <algorithm>
  8 using namespace std;
  9 
 10 const int maxn = 1e5+10;
 11 int A[maxn],B[maxn],mp[maxn],C[maxn];                                  // A 为原始数组, B为离散化之后的数组
 12 int n,m,tot,c[maxn*20],lson[maxn*20],rson[maxn*20];
 13 int build(int l,int r)
 14 {
 15     int root = tot++;
 16     c[root] = 0;
 17     if (l != r)
 18     {
 19         int mid = (l + r) >> 1;
 20         lson[root] = build(l,mid);
 21         rson[root] = build(mid+1,r);
 22     }
 23     return root;
 24 }
 25 int update(int root,int pos,int val)
 26 {
 27     int newroot = tot++;
 28     int tmp = newroot;
 29     int l = 1,r = n;
 30     c[newroot] = c[root] + val;
 31     while (l < r)
 32     {
 33         int mid = (l + r) >> 1;
 34         if (pos <= mid)
 35         {
 36             rson[newroot] = rson[root];
 37             root = lson[root];
 38             lson[newroot] = tot++;
 39             newroot = lson[newroot];
 40             r = mid;
 41         }
 42         else
 43         {
 44             lson[newroot] = lson[root];
 45             root = rson[root];
 46             rson[newroot] = tot++;
 47             newroot = rson[newroot];
 48             l = mid + 1;
 49         }
 50         c[newroot] = c[root] + val;
 51     }
 52     return tmp;
 53 }
 54 int query(int l_root,int r_root,int k)
 55 {
 56     int l = 1, r = n;
 57     while (l < r)
 58     {
 59         int mid = (l + r) >> 1;
 60         /*if (c[lson[r_root]] - c[lson[l_root]] >= k)
 61         {
 62             l_root = rson[l_root];
 63             r_root = rson[r_root];
 64             r = mid;
 65         }
 66         else
 67         {
 68             k -= (c[rson[r_root]] - c[rson[l_root]]);
 69             r_root = lson[r_root];
 70             l_root = lson[l_root];
 71             l = mid + 1;
 72         }*/
 73 
 74         if (c[lson[r_root]] - c[lson[l_root]] >= k)
 75         {
 76             r = mid;
 77             l_root = lson[l_root];
 78             r_root = lson[r_root];
 79         }
 80         else
 81         {
 82             l = mid + 1;
 83             k -=  c[lson[r_root]] - c[lson[l_root]];
 84             l_root = rson[l_root];
 85             r_root = rson[r_root];
 86         }
 87     }
 88     return l;
 89 }
 90 int per_root[maxn];
 91 int main(void)
 92 {
 93     #ifndef ONLINE_JUDGE
 94         freopen("in.txt","r",stdin);
 95     #endif
 96     while (~scanf ("%d%d",&n,&m))
 97     {
 98         tot = 0;
 99         for (int i = 1; i <= n; i++)
100         {
101             scanf ("%d",A+i);
102             C[i] = A[i];
103         }
104             
105         sort(A+1,A+n+1);
106         n = unique(A + 1, A + n + 1) - A - 1;
107 
108         for (int i = 1; i <= n; i++)
109         {
110             B[i] = lower_bound(A+1,A+n+1,C[i]) - A ;
111             mp[B[i]] = C[i];
112         }
113         per_root[0] = build(1,n);
114         for (int i = 1; i <= n; i++)
115         {
116             per_root[i] = update(per_root[i-1],B[i],1);
117         }
118         for (int i = 0; i < m; i++)
119         {
120             int l,r,k;
121             scanf ("%d%d%d",&l,&r,&k);
122             printf("%d
",mp[query(per_root[l-1],per_root[r], k)]);
123         }
124     }
125     return 0;
126 }
原文地址:https://www.cnblogs.com/oneshot/p/4113931.html