• 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 }
  • 相关阅读:
    CSS3权威指南 25.CSS3中的动画功能
    CSS3权威指南 24.CSS3中的变形处理
    CSS3权威指南 23.背景与边框相关样式
    CSS3权威指南 22.盒相关样式
    CSS3权威指南 20.使用选择器在页面中插入内容
    CSS3权威指南 19.选择器
    vivado中如何使用chipscope
    示波器X1探头和X10探头
    两个MMCM共享时钟输入时的严重警告和错误
    ZYNQ基础知识一
  • 原文地址:https://www.cnblogs.com/oneshot/p/4113931.html
Copyright © 2020-2023  润新知