蒟蒻来发题解了。我仔细看了一下其他题解,各位巨佬用了堆,红黑树,splay,treap之类的强大算法,表示蒟蒻的我只会口胡这些算法,所以我决定用一种极其易理解的算法————fhq treap,作为treap的升级版,它不仅好理解,好用,还能做到可持久化,真是神级算法(不知道为什么会fhq treap的我,不会一般treap)

进入正题,首先我先讲讲fhq treap的主要思想,它是一种非旋转的平衡树,不用考虑左旋右旋等麻烦情况,它很暴力,直接靠拆树,合并来实现,有点二分的感觉,其实它很多操作就有二分思想。

好了,看图,我们有一颗二叉树

当我们插入6号,发现它失衡了

多西太?大丈夫

我们不用旋转,不用交换,直接拆。

第一个重要操作:拆树(split),我们先把树分为x,y两部分,x的节点权值≤k, y的节点的权值>k,要插入一个数a的话,就把新的节点a看做是一棵树,先与x合并,合并完之后将合并的整体与y合并

上代码

 inline void split(int &x,int &y,int k,int pos)
{
if(!pos)x=y=;//root=0时(即第一次split) 此时的x=?,y=?很明显要给他们初始化 即x=0,y=0
else
{
if(val[pos]<=k)
{x=pos;split(son[pos][],y,k,son[pos][]);}
else
{y=pos;split(x,son[pos][],k,son[pos][]);}
update(pos);
}
}

第二个重要操作:合并(merge) 还是两棵树x,y。如果rand[x]<rand[y] 我们就把y接在x的右儿子上 你想如果接在左儿子 那左儿子的权值就大于父亲的权值了 不符合二叉搜索树的性质

反之同理

其实merge 要理解的话自己画两颗treap 然后模拟一下。

上代码

 inline int merge(int x,int y)
{
if(x==||y==) return x+y;//第一次合并的情况
if(rnd[x]<rnd[y])
{
son[x][]=merge(son[x][],y);
update(x);return x;
}
else
{
son[y][]=merge(x,son[y][]);
update(y);return y;
}
}

至于查排名(find),就是easy的操作了,根据堆的性质,直接找右子树大小,再去遍历就好了,不知道的可以先去学习二叉搜索树的操作(各位巨佬肯定都会了)

ac代码

 #include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 200010
using namespace std;
int n,val[maxn],rnd[maxn],son[maxn][],size[maxn],sum_p,m;
//val记录权值,son记录左右子树大小,size[i]记录以i为根节点的树的大小
int X1[maxn];
int flag[maxn];
inline void read(int &x)//快读
{
x=;int f=;
char ch=getchar();
while(ch<''||ch>'')
{if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='')
{x=x*+ch-'';ch=getchar();}
x*=f;
}
inline int newnode(int x)
{
++sum_p;size[sum_p]=;
val[sum_p]=x;rnd[sum_p]=rand();
return sum_p;
}
inline void update(int x)
{
size[x]=size[son[x][]]+size[son[x][]]+;//加上自己
}
inline void split(int &x,int &y,int k,int pos)//x,左子树的根(权值较小的),y,右子树的根,pos为现在的节点
{
if(!pos)x=y=;//root=0时(即第一次split) 此时的x=?,y=?所以初始化x=0,y=0
else
{
if(val[pos]<=k)
{x=pos;split(son[pos][],y,k,son[pos][]);}
else
{y=pos;split(x,son[pos][],k,son[pos][]);}
update(pos);
}
}
inline int merge(int x,int y)//保证y子树权值大于x子树
{
if(x==||y==) return x+y;//第一次合并的情况
if(rnd[x]<rnd[y]) //比rand大小
{
son[x][]=merge(son[x][],y);
update(x);return x;
}
else
{
son[y][]=merge(x,son[y][]);
update(y);return y;
}
}
inline int find(int pos,int rank)
{
while()
{
if(size[son[pos][]]>=rank)
{
pos=son[pos][];
}
else
if(size[son[pos][]]+==rank)return pos;//由于是儿子 要加上自己
else
{
rank-=size[son[pos][]]+;
pos=son[pos][];
}
}
}
int main()
{
srand((unsigned)time(NULL));
int a,b,x,y,z,op,root=,pos=;
read(n),read(m);
for(register int i=;i<=n;i++)
read(X1[i]);
for(register int i=;i<=m;i++)
{read(op);flag[op]++;}//记录查询点
for(register int i=;i<=n;i++)
{
split(x,y,X1[i],root);
root=merge(merge(x,newnode(X1[i])),y);
while(flag[i]>=)//可能一个位置不止一次查询
{
pos++;flag[i]--;
printf("%d\n",val[find(root,pos)]);
}
}
}

最后我再给没学过fhq treap的同学补充一点基础操作

1、求a的排名:我们只需要split成一颗≤a-1,一颗≥a的就行了 a的排名就是第一棵treap的size+1;

2、求a前驱:以a-1为界限拆树就好了,a的前驱肯定就是第一个treap里最大的 ,就在find操作的基础上,在x里找排名为size[x]的

3、求a后继:以a为界限拆树,a的后继是第二个treap里最小的;

4、delete和区间反转就留给大家自己思考了,无论如何,fhq treap的操作基本上都建立在拆树与合并上。

最后强烈安利一波fhq treap

题解 P1801 【黑匣子_NOI导刊2010提高(06)】的更多相关文章

  1. P1801 黑匣子_NOI导刊2010提高(06)

    P1801 黑匣子_NOI导刊2010提高(06) 题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个 ...

  2. Luogu P1801 黑匣子_NOI导刊2010提高(06)

    P1801 黑匣子_NOI导刊2010提高(06) 题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个 ...

  3. 洛谷 P1801 黑匣子_NOI导刊2010提高(06)(未完)

    P1801 黑匣子_NOI导刊2010提高(06) 题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个 ...

  4. 【洛谷】【堆】P1801 黑匣子_NOI导刊2010提高(06)

    [题目描述:] Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两 ...

  5. 【luogu P1801 黑匣子_NOI导刊2010提高(06)】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1801 替罪羊树吼啊! #include <cstdio> #include <cstrin ...

  6. 洛谷 P1801 黑匣子_NOI导刊2010提高(06) 题解

    昨晚恶补了一下二叉堆的内容 然后就找了几个二叉堆的题来做awa 然后发现用二叉堆做这题复杂度是O(nlogn) 但是有O(n)的解法 (某大佬这么说) 思路大概就是: 利用一个大根堆一个小根堆来维护第 ...

  7. [洛谷P1801]黑匣子_NOI导刊2010提高(06)

    题目大意:两个操作:向一个可重集中加入一个元素:询问第$k$大的数($k$为之前询问的个数加一) 题解:离散化,权值线段树直接查询 卡点:无 C++ Code: #include <cstdio ...

  8. 洛谷 P1801 黑匣子_NOI导刊2010提高(06)

    题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两种: ...

  9. luogu P1801 【黑匣子_NOI导刊2010提高(06)】

    这里提供一个简单实现新思路: . 约定: 以下n指代的数的数量,不是题目所指的n 以下m指代询问的数量,不是题目所指的m (不好意思,这是本人习惯) 分块+堆 **堆一次只能输出堆顶的一个元素,如果我 ...

随机推荐

  1. 探索SQL Server元数据(一)

    简介 在数据库中,我们除了存储数据外,还存储了大量的元数据.它们主要的作用就是描述数据库怎么建立.配置.以及各种对象的属性等.本篇简单介绍如何使用和查询元数据,如何更有效的管理SQLServer 数据 ...

  2. Java Memory Management

    How Memory works in Java The role of the stack - Each time you call a function, Java pushed the loca ...

  3. WPF软件开发系统之五——展会展厅触摸屏企业产品宣传展示系统

    本系统开发背景:上海展会多点触摸大屏(60寸以上)上互动展示. 功能包括:企业背景.产品.合作伙伴.所获荣誉等以图片.文字.视频多媒体的方式呈块状显示,亮点功能为支持多点操作去旋转.缩放.拖拽呈现各种 ...

  4. webapi读取上传的文件流

    逻辑说明 这里未引用System.Web.Mvc. 主要使用MultipartMemoryStreamProvider对象从Request中获取文件流. var provider = new Mult ...

  5. Azure按订阅,资源组,资源类型导出所有资源powershell命令

    一般可以借助powershell命令来读取资源:例如:1, 读取某个订阅下的资源:$subscriptionID = "xxxxxxxx"Set-AzureRmContext $s ...

  6. 【数据库】+ powerdesigner

    使用powerdesigner工具对现有数据库表 生成关系图:https://www.cnblogs.com/lusunqing/p/4128025.html 通过Excel生成PowerDesign ...

  7. tomcat 进程莫名停止

    背景: 有一次晚上下班,发完版,刚把电脑合上走到楼下,就接到报警,说是线上有一个tomcat进程不存在了,想着以为是误报,但是还是回去看看了,发现线上确实是刚才发版的项目,进程不存在了,想了想,刚才测 ...

  8. pm2 常用命令解析

    https://blog.csdn.net/chengxuyuanyonghu/article/details/74910875 (以上基本命令解析,一下补充) pm2 ecosystem  #在当前 ...

  9. redis 连接idea一直被拒绝

    网上查找的方法 方法一:idea中已经下载了Iedis 插件, 也导入了jar包 <!-- https://mvnrepository.com/artifact/commons-pool/com ...

  10. Spring Boot 2.x 编写 RESTful API (二) 校验

    用Spring Boot编写RESTful API 学习笔记 约束规则对子类依旧有效 groups 参数 每个约束用注解都有一个 groups 参数 可接收多个 class 类型 (必须是接口) 不声 ...