序列内第k小查询(线段树)
最近请教了一下大佬怎么求序列内第k大查询,自己又捣鼓了一下,虽然还没有懂得区间第k大查询,不过姑且做一个记录先吧
因为每个元素大小可能很大而元素之间不连续,所以我们先离散化处理一下,程序中的ori[ ]代表原序列,离散化后每个key对应一个值,mem[ ]存的是key对应的值:mem[i]代表离散化后 i 代表的值,a[i]代表离散化后有几个i对应的值(mem[i]的个数)
离散化之后建树,sum中存的是有序的元素总个数具体可以看程序,那么如何查询?我们查询线段树的sum,若tree[lid].sum >= k ,说明第k大一定在左儿子区间,因为线段树是以有序数列来构建的,每个叶子排起来是有序的(抠一下手指就出来了),说明k在左边。同理 若 tree[lid].sum < k 说明左边全部在一起都没有 k 个,答案自然就在右边了
因为从右边区间出发,已经排除全部左边节点了,所以k要减去左边的sum
这样一直找到叶子节点,找到的叶子对应的就是离散化后的key了,我们在利用mem输出就好
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
#define lid (id << 1)
#define rid (id << 1) | 1
const int maxn = 100019;
int num,na;
int ori[maxn];
int mem[maxn];
struct sag_tree{
int l,r,sum;
}tree[maxn << 2];
int a[maxn];
void build(int id,int l,int r){
tree[id].l = l;
tree[id].r = r;
if(l == r){
tree[id].sum = a[l];
return ;
}
int mid = (l + r) >> 1;
build(lid,l,mid);
build(rid,mid + 1,r);
tree[id].sum = tree[lid].sum + tree[rid].sum;
}
int query(int id,int k){
if(tree[id].l == tree[id].r)return tree[id].l;
if(tree[lid].sum < k)return query(rid,k - tree[lid].sum);
else if(tree[lid].sum >= k)return query(lid,k);
}
int main(){
num = RD();na = RD();
for(int i = 1;i <= num;i++){
ori[i] = RD();
}
sort(ori + 1,ori + 1 + num);
int n = 0;
for(int i = 1;i <= num;i++){
if(i == 1 || ori[i] != ori[i - 1]){
n++;
}
a[n]++;
mem[n] = ori[i];
}
build(1,1,n);
int k;
for(int i = 1;i <= na;i++){
k = RD();
cout<<mem[query(1,k)]<<endl;
}
return 0;
}
推一下可以得到,序列第k大就是序列第(num - k + 1)小,所以很好解决
upd 18.7.9
后面发现,其实这也是treap查找序列第k大的方法
序列内第k小查询(线段树)的更多相关文章
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 第一道线段树套线段树! 第一道标记永久化! 为什么为什么写了两个半小时啊…… 本想线段 ...
- ch1_5_2求无序序列中第k小的元素
import java.util.Arrays; import java.util.PriorityQueue; public class ch1_5_2求无序序列中第k小的元素 { public s ...
- 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树
题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...
- 「BZOJ3065」带插入区间第K小值 替罪羊树×线段树
题目描述 从前有\(n\)只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力\(a_i\).跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间\(k\)小值.他 ...
- 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树
[BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...
- 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树
经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...
- BZOJ 3065 带插入区间K小值 (替罪羊树套线段树)
毒瘤题.参考抄自博客:hzwer 第一次写替罪羊树,完全是照着题解写的,发现这玩意儿好强啊,不用旋转每次都重构还能nlognnlognnlogn. 还有外面二分和里面线段树的值域一样,那么r = mi ...
随机推荐
- php与nginx之间的通信
Nginx是俄国人最早开发的Webserver,现在已经风靡全球,相信大家并不陌生.PHP也通过二十多年的发展来到了7系列版本,更加关注性能.这对搭档在最近这些年,叱咤风云,基本上LNMP成了当下的标 ...
- Sprint会议2
昨天:准备查找安卓APP开发的有关资料,安装有关软件 今天:自己制作一个安卓小程序,熟悉一下操作 遇到问题:安装遇到问题,环境配置出现问题
- Chapter 5 软件工程中的形式化方法
从广义上讲,形式化方法是指将离散数学的方法用于解决软件工程领域的问题,主要包括建立精确的数学模型以及对模型的分析活动.狭义的讲,形式化方法是运用形式化语言,进行形式化的规格描述.模型推理和验证的方法. ...
- C#简单窗体应用程序(三)
使用C#创建窗体应用程序的基本步骤: (1)创建项目: (2)用户界面设计: (3)属性设置: (4)编写程序代码: (5)保存.调试.运行: 例题:设计歌曲列表界面,效果如下: 第一步:创建项目: ...
- 团队作业之404 Note Found Team
如果记忆是一个罐头的话,我希望这一罐罐头不会过期----<重庆森林> 404 Note Found Team 如果记忆是一个备忘录的话,别说了,它不会过期----<404 Note ...
- iOS完整学习路线图-对知识的回顾/整理
第一阶段:语言基础 Mac系统使用.常用UNIX指令.C语言.Objective-C语言.Foundation框架. 第二阶段:iOS基础 AppDelegate & UIApplicatio ...
- 1014 C语言文法定义与C程序的推导过程
<程序> -> <外部声明> | <程序> <外部声明> <外部声明> -> <函数定义> | <声明> ...
- [转帖]Nginx 的配置文件详解.
nginx配置文件nginx.conf超详细讲解 https://www.cnblogs.com/liang-wei/p/5849771.html #nginx进程,一般设置为和cpu核数一样w ...
- CSS 报错
- keydown和KeyPress事件有何不同
KEYPRESSWhen a windowed control receives a key-press message (WM_CHAR) from Windows, its message han ...