洛谷 [P1801] 黑匣子
这道题是一道splay裸题,然而身为蒟蒻的我并不会,所以这道题我维护的是一个大根堆与一个小根堆结合起来的类似沙漏的结构。
本题难点在于询问的不是最大最小值,而是第K小值,所以我们想到了维护这样两个堆,上面是一个大小限定为K-1的大根堆,下面是一个小根堆,每次插入/查询操作时,保持前K-1大的始终在大根堆内。
插入/查询函数:
int heap[200005][3],hsize[3];
int m,n,num[200005],temp;
void put(int x,int i){
heap[++hsize[i]][i]=x;
int son=hsize[i],pa=son>>1;
while(pa>=1){
if(i==1){
if(heap[pa][i]>heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
son=pa;
pa>>=1;
}else break;
}else {
if(heap[pa][i]<heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
son=pa;
pa>>=1;
}else break;
}
}
}
int get(int i){
int rv=heap[1][i];
heap[1][i]=heap[hsize[i]--][i];
int pa=1,son;
while(pa<=(hsize[i]>>1)){
if(i==1) son=heap[pa<<1][i]<heap[pa<<1|1][i]?pa<<1:pa<<1|1;
else son=heap[pa<<1][i]>heap[pa<<1|1][i]?pa<<1:pa<<1|1;
if(i==1){
if(heap[pa][i]>heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
pa=son;
}else break;
}else {
if(heap[pa][i]<heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
pa=son;
}else break;
}
}
return rv;
}
对整体的插入/查询:
void putt(int x){
put(x,1);
if(x==heap[1][1]){
get(1);
put(x,2);
int t=get(2);
put(t,1);
}
}
int gett(){
temp++;
int rv=get(1);
put(rv,2);
return rv;
}
附:跑得飞快的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
int read(){
int rv=0,fh=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') fh=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
rv=(rv<<1)+(rv<<3)+c-'0';
c=getchar();
}
return rv*fh;
}
int heap[200005][3],hsize[3];
int m,n,num[200005],temp;
void put(int x,int i){
heap[++hsize[i]][i]=x;
int son=hsize[i],pa=son>>1;
while(pa>=1){
if(i==1){
if(heap[pa][i]>heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
son=pa;
pa>>=1;
}else break;
}else {
if(heap[pa][i]<heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
son=pa;
pa>>=1;
}else break;
}
}
}
int get(int i){
int rv=heap[1][i];
heap[1][i]=heap[hsize[i]--][i];
int pa=1,son;
while(pa<=(hsize[i]>>1)){
if(i==1) son=heap[pa<<1][i]<heap[pa<<1|1][i]?pa<<1:pa<<1|1;
else son=heap[pa<<1][i]>heap[pa<<1|1][i]?pa<<1:pa<<1|1;
if(i==1){
if(heap[pa][i]>heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
pa=son;
}else break;
}else {
if(heap[pa][i]<heap[son][i]){
int t=heap[pa][i];heap[pa][i]=heap[son][i];heap[son][i]=t;
pa=son;
}else break;
}
}
return rv;
}
void putt(int x){
put(x,1);
if(x==heap[1][1]){
get(1);
put(x,2);
int t=get(2);
put(t,1);
}
}
int gett(){
temp++;
int rv=get(1);
put(rv,2);
return rv;
}
int f[200005];
int main(){
freopen("in.txt","r",stdin);
m=read();n=read();
for(int i=1;i<=m;i++){
num[i]=read();
}
for(int i=1;i<=n;i++){
f[read()]++;
}
for(int i=1;i<=m;i++){
putt(num[i]);
while(f[i]){
printf("%d\n",gett());
f[i]--;
}
}
/*for(int i=1;i<=10000;i++){
put(rand(),2);
}
for(int i=1;i<=10000;i++){
printf("%d ",get(2));
}*/
fclose(stdin);
return 0;
}
洛谷 [P1801] 黑匣子的更多相关文章
- 洛谷 P1801 黑匣子_NOI导刊2010提高(06)(未完)
P1801 黑匣子_NOI导刊2010提高(06) 题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个 ...
- 洛谷 - P1801 - 黑匣子 - 对顶堆
这道题是提高+省选-的难度,做出来的话对数据结构题目的理解会增加很多. 可以使用一种叫做对顶堆的东西,对顶堆是在线维护第n小的logn的算法.大概的思路是,假如我们要找的是第n小,我们就维护一个大小为 ...
- 洛谷P1801 黑匣子
题目传送门 分析:这题和另外一个题目中位数非常相似,有兴趣可以先看看,比这一题简单.首先暴力模拟还是别想了,估计30%的数据都有点悬.正解应该是用二叉堆.但是如果用一个堆当然不方便,所以建两个堆,一个 ...
- [洛谷P1801]黑匣子_NOI导刊2010提高(06)
题目大意:两个操作:向一个可重集中加入一个元素:询问第$k$大的数($k$为之前询问的个数加一) 题解:离散化,权值线段树直接查询 卡点:无 C++ Code: #include <cstdio ...
- 洛谷 P1801 黑匣子_NOI导刊2010提高(06)
题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两种: ...
- 洛谷 P1801 黑匣子_NOI导刊2010提高(06) 题解
昨晚恶补了一下二叉堆的内容 然后就找了几个二叉堆的题来做awa 然后发现用二叉堆做这题复杂度是O(nlogn) 但是有O(n)的解法 (某大佬这么说) 思路大概就是: 利用一个大根堆一个小根堆来维护第 ...
- 洛谷 P1801 黑匣子 题解
题面 离线处理: 大体思路就是将数组排序,然后对于第k次询问把不可行的数打上标记,然后从头开始寻找第k个没打标记的点的值(排序后的数组保证了它是第k小的). 实现方法:首先离散化原始数组,得到数组fi ...
- 【洛谷P1801】黑匣子
黑匣子 题目链接 看到题解中“维护两个堆”,突然想到了这道题的解法 维护两个堆:大根堆h1, 小根堆h2 大根堆里的是最小的i个值,小根堆里是剩下的值 每Add一个值时 插入到小根堆中, 再比较小根堆 ...
- 「洛谷 P1801」黑匣子
好像很久没有更过博客了,因为博主这几周很忙.其实是在搞颓. 题意很难懂,所以就不重复了.其实是懒. 一眼看上去这是个 \(Splay\) 裸题,直接插入一个数,查询区间第 \(K\) 大,但是这样太不 ...
随机推荐
- c+(内存)
内存是程序运行的基础.所有正在运行的代码都保存在内存里面.内存需要处理各种各样的数据,包括键盘的数据.鼠标的数据.usb的数据.串口的数据.摄像头的数据,那么这些数据经过程序的处理之后,就要进行输出到 ...
- java实现死锁的demo
死锁 只有当t1线程占用o1且正好也需要o2,t2此时占用o2且正好也需要o1的时候才会出现死锁,(类似于2个人拿着两个筷子吃饭,都是需要对方的一根筷子才能吃) 以下代码t1线程占用o1,并且获取到o ...
- 《图解http》知识点笔记
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica } p.p2 { margin: 0.0px 0.0px 0.0px 0. ...
- CentOS系统下Redis安装和自启动配置的步骤
相信大家都知道Redis是一个C实现的基于内存.可持久化的键值对数据库,在分布式服务中常作为缓存服务.所以这篇文章将详细介绍在CentOS系统下如何从零开始安装到配置启动服务.有需要的可以参考借鉴. ...
- linux一键安装
http://source.docs.cloudcare.cn/support/faq/webfaq/webfaq_11/?spm=5176.730006-cmgj000262.102.8.QsmPR ...
- 分析业务模型-类图(Class Diagram)
分析业务模型-类图(Class Diagram) 分析业务模型-类图(Class Diagram)(上) 摘要:类图(Class Diagram)可能是用得最多的一种UML图.类图的基本语法并 ...
- linux各种顔色代表
@linux中的各文件的颜色表示什么 白色:表示普通文件 蓝色:表示目录 绿色:表示可执行文件 红色:表示压缩文件 浅蓝色:链接文件 红色闪烁:表示链接的文件有问题 黄色:表示设备文件 灰色:表示其它 ...
- junit4X系列源码--总体介绍
原文出处:http://www.cnblogs.com/caoyuanzhanlang/p/3530267.html.感谢作者的无私分享. Junit是一个可编写重复测试的简单框架,是基于Xunit架 ...
- linux相关概念
最近这段时间玩Linux比较多,前面我也转载了好多的相关的Linux指令.这里自己关于Linux概念来自己整理一下. 首先我们应该知道Linux到底是什么? 我们知道Linux这玩意儿是在计算机上面运 ...
- linkin大话java
青春不灭,理想犹存,linkin--勿忘初心! 不知不觉已经和java并肩作战将近了2年,在这2年之中模模糊糊研究了java2ee领域的好多东西,但是都没有做系统的整理.以前写的笔记也是零零散散不成一 ...