zoukankan      html  css  js  c++  java
  • 静态主席树

    【转】主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化),记录该前缀序列里出现的值的次数;记离散后的标记为1~n; (下面值直接用1~n代替;) 

    对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始,t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数 先判断t是否大于K。

    如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k,也就是第k大的值在[1,mid]中,否则在[mid+1,r]中;

    这样我们依次同时从root[x-1],root[y]往下走当l==r时 第k大的值就是离散后标记为l的值

    ;如果每棵线段都建完整的化,n*(n<<2)肯定会mle,我们发现对于前缀[1,i]和前缀[1,i+1]的线段树,如果b[i+1]<=mid (b[i+1]表示a[i+1]离散后的标记)那么线段树i和线段树i+1的左边是完全相同的,根本不需要再建,只需要用指针指一下就好;那么对于一棵新的线段树其实我们最多要建的节点数为log(n);nlog(n)的节点数还是可以忍受的;

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 using namespace std;
     7 const int maxn = 10000 + 10;
     8 const int maxnn = 100 * maxn;
     9 int n, Q, ms, tot;
    10 int root[maxn], A[maxn], ls[maxnn], rs[maxnn], s[maxnn];
    11 int num[maxn], hash[maxn];
    12 int find(int x){
    13     int L = 1, R = tot, M;
    14     while(L <= R){
    15         M = L + R >> 1;
    16         if(hash[M] < x) L = M + 1;
    17         else R = M - 1;
    18     }
    19     return L;
    20 }
    21 void build(int x, int& y, int L, int R, int v){
    22     s[y = ++ ms] = s[x] + 1;
    23     if(L == R) return;
    24     ls[y] = ls[x]; rs[y] = rs[x];
    25     int M = L + R >> 1;
    26     if(v <= M) build(ls[x], ls[y], L, M, v);
    27     else build(rs[x], rs[y], M + 1, R, v);
    28     return ;
    29 }
    30 int query(int x, int y, int L, int R, int k){
    31     if(L == R) return L;
    32     int M = L + R >> 1, kth = s[ls[y]] - s[ls[x]];
    33     if(kth >= k) return query(ls[x], ls[y], L, M, k);
    34     else return query(rs[x], rs[y], M + 1, R, k - kth);
    35 }
    36 void read(int &x){
    37     x = 0; int sig = 1; char ch = getchar();
    38     while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); }
    39     while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
    40     x *= sig; return ;
    41 }
    42 void init(){
    43     read(n); read(Q);
    44     for(int i = 1; i <= n; i ++) read(A[i]), num[i] = A[i];
    45     sort(num + 1, num + n + 1); hash[++ tot] = num[1];
    46     for(int i = 2; i <= n; i ++) if(num[i] != num[i - 1]) hash[++ tot] = num[i];
    47     for(int i = 1; i <= n; i ++) build(root[i - 1], root[i], 1, tot, find(A[i]));
    48     return ;
    49 }
    50 void work(){
    51     int _i, _j, _k;
    52     while(Q --){
    53         read(_i); read(_j); read(_k);
    54         printf("%d
    ", hash[query(root[_i - 1], root[_j], 1, tot, _k)]);
    55     }
    56     return ;
    57 }
    58 void print(){
    59 
    60     return ;
    61 }
    62 int main(){
    63     init();
    64     work();
    65     print();
    66     return 0;
    67 }
  • 相关阅读:
    [idea]2014.1.13
    [idea]2014.1.12
    纪念我2014.1.4 中国银行广东分行面试
    [essay]2014.1.2
    纪念我12月29日南方电网笔试
    [essay]12.26
    [idea]
    纪念我12月24日终于用妖姬拿首胜了
    Android自动化测试环境部署
    Monitor工具使用详解
  • 原文地址:https://www.cnblogs.com/chxer/p/4394720.html
Copyright © 2011-2022 走看看