博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]
阅读量:4708 次
发布时间:2019-06-10

本文共 2656 字,大约阅读时间需要 8 分钟。

  

可持久化线段树1(主席树)

题目背景

这是个非常经典的主席树入门题——静态区间第K小

数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入输出格式

输入格式:

 

第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

第二行包含N个正整数,表示这个序列各项的数字。

接下来M行每行包含三个整数 $l,r,k$ , 表示查询区间 $[l,r]$ 内的第k小值。

 

输出格式:

 

输出包含k行,每行1个正整数,依次表示每一次查询的结果

 

输入输出样例

输入样例#1: 
5 525957 6405 15770 26287 26465 2 2 13 4 14 5 11 2 24 4 1
输出样例#1: 
640515770262872595726287

说明

数据范围:

对于20%的数据满足: $1 \leq N, M \leq 10$

对于50%的数据满足: $1 \leq N, M \leq 10^3$

对于80%的数据满足: $1 \leq N, M \leq 10^5$

对于100%的数据满足: $1 \leq N, M \leq 2\cdot 10^5$

对于数列中的所有数 $a_i$​ ,均满足 $-{10}^9 \leq a_i \leq {10}^9$

样例数据说明:

N=5,数列长度为5,数列从第一项开始依次为 $[25957,6405,15770,26287,26465]$

第一次查询为 $[2,2]$ 区间内的第一小值,即为6405

第二次查询为 $[3,4]$ 区间内的第一小值,即为15770

第三次查询为 $[4,5]$ 区间内的第一小值,即为26287

第四次查询为 $[1,2]$ 区间内的第二小值,即为25957

第五次查询为 $[4,4]$ 区间内的第一小值,即为26287

 


  分析:

  主席树入门题。

  一直说要学习主席树来的,但是直到今天才实现。主席树的具体思想蒟蒻就不再赘述,只说下$k$小值查询如何实现。查询静态$k$小值的时候在主席树中存储的是一个权值,也就是说我们把这棵主席树当做一颗权值树。现将数据离散,然后按照原顺序依次插入线段树中,从根节点开始往下直到找到第该元素排名个数个的线段树中节点的位置,将沿途经过的每个节点的记录的值+1。这样的话根据线段树中的权值就可以用一种类似于平衡树查询$k$小值的方法来查询。具体实现看代码。

  Code:

 

//It is made by HolseLee on 29th July 2018//Luogu.org P3834#include
using namespace std;const int N=2e5+7;int n,m,tot,cnt,a[N],b[N],rk[N],rt[N];struct President_tree{ int ls,rs,sum;}t[N*20];int read(){ char ch=getchar();int num=0;bool flag=false; while(ch<'0'||ch>'9'){
if(ch=='-')flag=true;ch=getchar();} while(ch>='0'&&ch<='9'){num=(num<<3)+(num<<1)+ch-'0';ch=getchar();} return flag?-num:num;}inline void build(int l,int r,int &node){ node=++cnt; if(l==r)return ; int mid=(l+r)>>1; build(l,mid,t[node].ls); build(mid+1,r,t[node].rs);}inline void update(int l,int r,int &node,int last,int tar){ node=++cnt;t[node]=t[last];++t[node].sum; if(l==r)return; int mid=(l+r)>>1; if(tar<=mid)update(l,mid,t[node].ls,t[last].ls,tar); else update(mid+1,r,t[node].rs,t[last].rs,tar);}inline int quary(int l,int r,int node,int last,int tar){ if(l==r)return a[l]; int now=t[t[node].ls].sum-t[t[last].ls].sum,mid=(l+r)>>1; if(tar<=now)return quary(l,mid,t[node].ls,t[last].ls,tar); else return quary(mid+1,r,t[node].rs,t[last].rs,tar-now);}int main(){ n=read();m=read(); for(int i=1;i<=n;++i){ a[i]=read();b[i]=a[i]; } sort(a+1,a+n+1); tot=unique(a+1,a+n+1)-a-1; build(1,tot,rt[0]); for(int i=1;i<=n;++i) rk[i]=lower_bound(a+1,a+tot+1,b[i])-a; for(int i=1;i<=n;i++) update(1,tot,rt[i],rt[i-1],rk[i]); int l,r,k; for(int i=1;i<=m;++i){ l=read();r=read();k=read(); printf("%d\n",quary(1,tot,rt[r],rt[l-1],k)); } return 0;}

 

转载于:https://www.cnblogs.com/cytus/p/9385383.html

你可能感兴趣的文章
互联网架构消息队列
查看>>
day5_生成进度条的程序
查看>>
Linux内核之于红黑树and AVL树
查看>>
招聘一个靠谱的iOS
查看>>
使用Xunit进行单元测试
查看>>
TCP的三次握手和四次握手
查看>>
创建用户、授权SCHEMA
查看>>
python学习笔记
查看>>
zoj 3229 有源汇有上下界的最大流模板题
查看>>
Python使用mechanize模拟浏览器
查看>>
android调用音乐播放器,三种方
查看>>
read/sysread区别
查看>>
《JavaScript高级程序设计》阅读笔记(十八):跨平台的事件
查看>>
长列表优化之滚动替换数据方案小记
查看>>
20180827 360笔试客观题
查看>>
【转】使用YCSB测试mongodb分片集群性能
查看>>
StartSSL免费证书申请笔记
查看>>
Server.MapPath查询路径那几件事
查看>>
简单易懂的snmpd.conf配置文件说明
查看>>
引用 IP电话的原理结构及其关键技术
查看>>