题目背景

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

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

题目描述

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

输入输出格式

输入格式:

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

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制

5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出样例#1: 复制

6405
15770
26287
25957
26287

题面非常清晰,区间第k大。首先,每次排序再还原肯定是要跪的。

这时主席树就出现了。

主席树,倒不如说是榕树(有多个根节点,但是却不是森林)。可以说是在用空间换时间。

其实这题,主席树的主体应该是一棵权值线段树。

别人都说主席树是在每个位置维护了一颗线段树,我一直以为是每一个叶节点,其实是在每一个...好吧就是叶节点。

这里可能要把历史值那一题拿出来讲讲,主席树的每一次修改只修改一条链,而不是整个换血,所以为我们的查询提供了方便。

模拟一发:

7 1

1 5 2 6 3 7 4

建树:(感谢@bestFy的数据和图!)


插完所有的之后:

(妥妥的权值线段树)

最终图只是最后一棵线段树的样子,之前的各个线段树依旧在保存着。

于是就出现了旧节点和新建的节点公用一个根节点的情况。于是就可以愉快地进行差分了(因为两个新旧节点是等价的啊)

∴两棵线段树的对应节点相减就是对应区间有的数字啦

所以对于一个区间[l, r],我们可以每次算出在[l, mid]范围内的数,如果数量>=k(k就是第k大),就往左子树走,否则就往右子树走。

于是区间第k大就完成了。

贴代码:

#include<bits/stdc++.h>
变量解释:sum:节点的总数
rt:新旧树的根节点
ls:左儿子
rs:右儿子
tot:当前节点编号
using namespace std;
const int maxn=;
int n,m,tot,sum[maxn<<],rt[maxn<<],ls[maxn<<],rs[maxn<<],a[maxn],b[maxn],len; int build(int l,int r)
{
int root=++tot;//每新建一个节点(根)
if(l==r) return root;//如果到叶节点了返回根的值,我们要记录下来
int mid=l+r>>;//二分区间
ls[root]=build(l,mid);//记录下一层的根,也就是左儿子
rs[root]=build(mid+,r);//同上
return root;//返回大根
}
int updata(int l,int r,int root,int k)
{
int newroot=++tot;//新建的根的编号
ls[newroot]=ls[root];//记录
rs[newroot]=rs[root];//建一个等价的节点,左右儿子也是旧根节点的左右儿子
sum[newroot]=sum[root]+;//每新建一条链增加一个有值的点,所以+1(权值线段树)
if(l==r) return newroot;
int mid=l+r>>;
if(k<=mid) ls[newroot]=updata(l,mid,ls[newroot],k);//
else rs[newroot]=updata(mid+,r,rs[newroot],k);
return newroot;
}
int query(int fl,int fr,int l,int r,int k)
{
int mid=l+r>>,x=sum[ls[fr]]-sum[ls[fl]];//查询区间里的东西,先遍历左儿子,不行再往右跑
if(l==r) return l;
else if(k<=x) return query(ls[fl],ls[fr],l,mid,k);//差分了
else return query(rs[fl],rs[fr],mid+,r,k-x);//差分了
}
int main()
{
int i,x,l,r,k;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,b++n);
len=unique(b+,b++n)-b-;//去重,神仙操作
//printf("%d\n",len);
rt[]=build(,len);//根的“tot”(下标,第几个点)
for(i=;i<=n;i++)//要对每一个节点建树,所以n次加边
{
x=lower_bound(b+,b++len,a[i])-b;//离散化,更新相对大小,也就是把所有数的编号弄小
rt[i]=updata(,len,rt[i-],x);//新根的编号
}
for(i=;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",b[query(rt[l-],rt[r],,len,k)]);//query返回的是下标,所以要这么长一串。。
}
for(int i=;i<=*n;i++)
{
//if(sum[i]==0)break;
printf("%d ",sum[i]);
}
return ;
}

(完)


主席树学习笔记(静态区间第k大)的更多相关文章

  1. ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

    Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树 ...

  2. 线段树专题2-(加强版线段树-可持续化线段树)主席树 orz! ------用于解决区间第k大的问题----xdoj-1216

    poj-2104(区间第K大问题) #include <iostream> #include <algorithm> #include <cstdio> #incl ...

  3. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

  4. HDU3473--Minimum Sum(静态区间第k大)

    Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  5. poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 43315   Accepted: 14296 Ca ...

  6. 主席树(静态区间第k大)

    前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...

  7. 静态区间第k大(归并树)

    POJ 2104为例 思想: 利用归并排序的思想: 建树过程和归并排序类似,每个数列都是子树序列的合并与排序. 查询过程,如果所查询区间完全包含在当前区间中,则直接返回当前区间内小于所求数的元素个数, ...

  8. 主席树初步学习笔记(可持久化数组?静态区间第k大?)

    我接触 OI也快1年了,然而只写了3篇博客...(而且还是从DP跳到了主席树),不知道我这个机房吊车尾什么时候才能摸到大佬们的脚后跟orz... 前言:主席树这个东西,可以说是一种非常畸形的数据结构( ...

  9. HDU 2665 Kth number(主席树静态区间第K大)题解

    题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...

随机推荐

  1. 04、JDBC范例

    范例:JDBC查询 package com.hsp; import java.sql.Connection; import java.sql.DriverManager; import java.sq ...

  2. node与mysql的相互使用————node+mysql

    node与mysql的相互使用----node+mysql 为什么选node???因为我是个前端. 为什么选mysql???因为成熟,稳定,听说容易学. 一.mysql数据库: mysql下载和使用我 ...

  3. # Ubuntu16.04安装nvidia驱动+CUDA+cuDNN

    Ubuntu16.04安装nvidia驱动+CUDA+cuDNN 准备工作 1.查看GPU是否支持CUDA lspci | grep -i nvidia 2.查看Linux版本 uname -m &a ...

  4. SEER区块浏览器开发指南

    区块浏览器基本功能 区块链浏览器是浏览区块链信息的主要窗口,每一个区块所记载的内容都可以从区块链浏览器上进行查阅.用户可以使用区块链浏览器查询记录在区块中的交易信息,包括转账.预测.账户管理和社区治理 ...

  5. django-Xadmin后台管理

    0919自我总结 django-Xadmin后台管理 一.安装环境 pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 ...

  6. ‎Cocos2d-x 学习笔记(22) TableView

    [Cocos2d-x 学习笔记 ]目录 1. 简介 TableView直接继承了ScrollView和ScrollViewDelegate.说明TableView能实现ScrollView拖动cont ...

  7. 在博客中增加自己的live2d纸片人模型方法

    目录 在博客中增加自己的live2d纸片人模型 准备工具 使用步骤 附件 在博客中增加自己的live2d纸片人模型 准备工具 github仓库:存放live2d模型和json文件 如果你的博客支持本地 ...

  8. hadoop-3.1.2启动httpfs

    最近有一个需求,要求使用httpfs读取数据,一开始看到httpfs这个词,第一感觉是不是多了个f,是不是https,后来百度一下,其实不然. httpfs其实是使用http协议访问hdfs文件系统: ...

  9. js检测页面上一个元素是否已经滚动到了屏幕的可视区域内

    应用场景:只要页面加载了,其中在页面中出现的li就向控制台输出第几个发送请求:在本次加载的页面中,再将滚动条滚回前边的li,不再向控制台输出东西,也就是说已经显示过的li,不再向控制台输出东西. &l ...

  10. Mutex vs Semaphore vs Monitor vs SemaphoreSlim

    C#开发者(面试者)都会遇到Mutex,Semaphore,Monitor,SemaphoreSlim这四个与锁相关的C#类型,本文期望以最简洁明了的方式阐述四种对象的区别. 线程安全 教条式理解 如 ...