• 第k大的数(主席树模板)


    描述

    你为Macrohard公司的数据结构部门工作,你的工作是重新写一个数据结构,这个数据结构能快速地找到一段数列中第k大的数。

    就是说,给定一个整数数列a[1..n],其中每个元素都不相同,你的程序要能回答一组格式为Q (i , j , k)的查询,Q(i, j ,k)的意思是“在a[i..j]中第k大的数是多少?”

    例如令 a = {1, 5, 2, 6, 3, 7, 4},查询格式为Q (2 , 5 , 3),数列段a[2..5] = {5, 2, 6, 3},第3大的数是5,所以答案是5。

    输入

    文件第一行包括一个正整数n,代表数列的总长度,还有一个数m,代表有m个查询。 n,m满足:1≤n≤100 000, 1≤m≤5 000 第二行有n个数,代表数列的元素,所有数都不相同,而且不会超过109 接下来有m行,每行三个整数i , j , k,代表一次查询, i , j , k满足1≤i≤j≤n, 1≤k≤j − i + 1

    输出

    输出每个查询的答案,用换行符隔开

    样例输入[复制]
    7 3
    1 5 2 6 3 7 4
    2 5 3
    4 4 1
    1 7 3
    样例输出[复制]
    5
    6
    3
     
     
     
     1 /*template of chair tree 
     2 lower_bound函数是用来返回一个值在单调递增数列里大于等于这个值的最小值
     3 upper_bound函数实际上就是将lower_bound里面的大于等于改成了严格大于 
     4 这里p的作用仅仅是在记录这个点的编号,我们用一维数组来存储树,只是该指向哪个位置 
     5 同时我们输入了几个数就维护那么大的区间,不一定一定要从1枚举到最大值,比如说1,8,5,4
     6 仅需要四个数组位置,我每往后加一个数字就要建一棵节约空间的线段树,类似于AC自动机的思想
     7 那么这个数组对应的a数组就是 1,4,3,2,每加一个就相当于一个节点修改了值然后向上维护,不过这
     8 里没有使用pushup函数,而是直接在二分的过程中进行累加,可以更好地维护值 
     9 为什么我们要维护这么多棵线段树,因为我们要像前缀和数组一样通过一个版本减去前面的版本
    10 来获得所需区间的排序信息,再进行二分就可以了. 
    1112 */ 
    13 #include<bits/stdc++.h>
    14 #define N 100005
    15 using namespace std;
    16 struct Node{
    17     int l,r,sum;
    18 }T[N*40];
    19 int a[N],b[N],n,m,rt[N*40];
    20 int tot=0;
    21 inline void build(int &p,int l,int r){//初始建图 
    22     p=++tot;
    23     T[p].sum=0;
    24     if(l==r)return;
    25     int mid=(l+r)>>1;
    26     build(T[p].l,l,mid);
    27     build(T[p].r,mid+1,r);
    28 }
    29 inline void update(int &p,int l,int r,int o,int k){
    30 /*几个变量分别表示为当前节点的编号/左端点/右端
    31 点/上一棵线段树/原数组该值对应的名次*/ 
    32     p=++tot;// 这个点的编号就是新开空间 ,这个空间对应的下标就是这个点,不是值 
    33     T[p].sum=T[o].sum+1;//由于是更新一个值,所以沿途走下去的链(要更新的点)中都要比上一个版本多1 
    34     T[p].l=T[o].l;//
    35     T[p].r=T[o].r;
    36     if(l==r)return;//如果已经到叶节点了,那么就代表更新结束 
    37     int mid=(l+r)>>1;//进行二分 
    38     if(k<=mid)update(T[p].l,l,mid,T[o].l,k);
    39     else update(T[p].r,mid+1,r,T[o].r,k);
    40 }
    41 inline int query(int p1,int p2,int l,int r,int k){
    42     if(l==r)return l;//这里的l和r如果相同,就是指这个k大就是在这个节点,而且这个节点的下标(对应到b)会被返回 
    43     int t=T[T[p2].l].sum-T[T[p1].l].sum;//两棵线段树作差 
    44     int mid=(l+r)>>1;//进行二分 
    45     if(t>=k)return query(T[p1].l,T[p2].l,l,mid,k);
    46     else return query(T[p1].r,T[p2].r,mid+1,r,k-t);
    47 }
    48 inline long long read(){
    49     long long ans=0,w=1;
    50     char ch=getchar();
    51     while(!isdigit(ch)){
    52         if(ch=='-')w=-1;
    53         ch=getchar();
    54     }
    55     while(isdigit(ch)){
    56         ans=(ans<<3)+(ans<<1)+ch-'0';
    57         ch=getchar();
    58     }
    59     return ans*w;
    60 }
    61 inline void write(long long x){
    62     if(x<0){
    63         putchar('-');
    64         x=-x;
    65     }
    66     if(x>9)write(x/10);
    67     putchar(x%10+'0');
    68 }
    69 int main(){
    70     n=read();
    71     m=read();
    72     for(int i=1;i<=n;++i){
    73         a[i]=read();
    74         b[i]=a[i];//复制数组用lower_bound函数查找位置 
    75     }
    76     sort(b+1,b+n+1);//lower_bound函数必须是严格单调递增,配合unique函数 
    77     int siz=unique(b+1,b+n+1)-b-1;//进行去重操作 
    78     build(rt[0],1,siz);//对第0棵树进行建图 
    79     for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+siz+1,a[i])-b;
    80     /*找到a[i]该在的位置,此时a数组的作
    81     用变为了记录对应数字应该在的下标 ,
    82     类似于一般我们是数组下标对应值,而
    83     这里新加的操作就是原数列的每个值
    84     应该对应到排序过后的第几个位置,
    85     相当于第几名
    86     */
    87     for(int i=1;i<=n;++i)update(rt[i],1,siz,rt[i-1],a[i]);
    88     while(m--){
    89         int ql=read(),qr=read(),k=read();
    90         write(b[query(rt[ql-1],rt[qr],1,siz,k)]);
    91         puts("");
    92     }
    93     return 0;
    94 }
  • 相关阅读:
    .Net Core调用NodeJs
    ASP.NET Core中间件中渲染Razor视图
    ASP.NET Core自定义View查找路径,实现主题切换
    Core路由2-Endpoint终结点路由
    Core路由1
    .NET Core的本地化机制(多语言)【转】
    实现ASP.NET Core MVC的插件式开发(ApplicationPart)
    Gitflow工作流程
    Git-开发中遇到紧急任务如何处理
    多线程笔记-CancellationToken(取消令牌)
  • 原文地址:https://www.cnblogs.com/saionjisekai/p/9548631.html
Copyright © 2020-2023  润新知