zoukankan      html  css  js  c++  java
  • 主席树 静态区间第k大

     1 /*
     2 主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化),
     3 记录该前缀序列里出现的值的次数;
     4 记离散后的标记为1~n; (下面值直接用1~n代替;) 
     5 对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始,
     6 t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数 
     7 先判断t是否大于K,如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k,
     8 也就是第k大的值在[1,mid]中,否则在[mid+1,r]中;
     9 
    10 这样我们依次同时从root[x-1],root[y]往下走
    11 当l==r时 第k大的值就是离散后标记为l的值;
    12 
    13 如果每棵线段都建完整的化,n*(n<<2)肯定会mle,
    14 我们发现对于前缀[1,i]和前缀[1,i+1]的线段树,如果b[i+1]<=mid (b[i+1]表示a[i+1]离散后的标记)
    15 那么线段树i和线段树i+1的左边是完全相同的,根本不需要在建,只需要用指针指一下就好;
    16 那么对于一棵新的线段树其实我们最多要建的节点数为log(n);nlog(n)的节点数还是可以忍受的;
    17  
    18 
    19  
    20 */
    21 #include<cstdio>
    22 #include<cstring>
    23 #include<iostream>
    24 #include<algorithm>
    25 #include<cmath>
    26 #include<cstdlib>
    27 #define w(i) T[(i)].w
    28 #define ls(i) T[(i)].ls
    29 #define rs(i) T[(i)].rs
    30 using namespace std;
    31 const int N=100000+10;
    32 struct node{
    33     int ls,rs,w;
    34     node(){ls=rs=w=0;}
    35 }T[N*20];
    36 int a[N],b[N],p[N],root[N],sz;
    37 int cmp(int i,int j){
    38     return a[i]<a[j];
    39 }
    40 int n,m;
    41 void ins(int &i,int l,int r,int x){
    42     T[++sz]=T[i]; i=sz;
    43     w(i)++;
    44     if (l==r) return;
    45     int m=(l+r)>>1;
    46     if (x<=m) ins(ls(i),l,m,x);
    47     else ins(rs(i),m+1,r,x);
    48 }
    49 int query(int i,int j,int l,int r,int k){
    50     if (l==r) return l;
    51     int t=w(ls(j))-w(ls(i));
    52     int m=(l+r)>>1;
    53     if (t>=k) return query(ls(i),ls(j),l,m,k);
    54     else return query(rs(i),rs(j),m+1,r,k-t);
    55 }
    56 int main(){
    57     int Cas;scanf("%d",&Cas);
    58     while (Cas--){
    59         root[0]=0;
    60         scanf("%d%d",&n,&m);
    61         for (int i=1;i<=n;i++){
    62             scanf("%d",&a[i]);p[i]=i;
    63         }
    64         sort(p+1,p+1+n,cmp);//间接排序,p[i]表示第i小的值在a[]中的下标; 
    65         for (int i=1;i<=n;i++) b[p[i]]=i;//离散化 
    66         /*
    67         for (int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
    68         for (int i=1;i<=n;i++) cout<<p[i]<<" ";cout<<endl;
    69         for (int i=1;i<=n;i++) cout<<b[i]<<" ";cout<<endl;
    70         */
    71         sz=0;
    72         for (int i=1;i<=n;i++){
    73             root[i]=root[i-1];
    74             ins(root[i],1,n,b[i]);
    75         }
    76         for (int i=0;i<m;i++){
    77             int x,y,k;scanf("%d%d%d",&x,&y,&k);
    78             int t=query(root[x-1],root[y],1,n,k);
    79             printf("%d\n",a[p[t]]);
    80         }
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    log4j.appender.stdout.layout.ConversionPattern
    log4j:WARN No appenders could be found for logger
    Eclipse中TODO的分类,以及自动去除
    Java泛型类型擦除导致的类型转换问题
    Java中泛型数组的使用
    Java泛型中的通配符的使用
    Java泛型类定义,与泛型方法的定义使用
    Java泛型的类型擦除
    jQuery查询性能考虑
    jQuery判断checkbox是否选中
  • 原文地址:https://www.cnblogs.com/Rlemon/p/3094635.html
Copyright © 2011-2022 走看看