【洛谷P3369】 (模板)普通平衡树
https://www.luogu.org/problemnew/show/P3369
Splay模板
#include<iostream>
#include<cstdio>
using namespace std;
#define MAXN 100010
int n,sons[MAXN][],f[MAXN],size[MAXN],cnt[MAXN],value[MAXN],root,Size;
inline int read(){ //快读
int x=,ff=; char c=getchar();
while(c<''||c>'') { if(c=='-') ff=-; c=getchar(); }
while(''<=c&&c<='') { x=(x<<)+(x<<)+c-''; c=getchar(); }
return x*ff;
}
inline void clear(int x){ //清除节点x
f[x]=sons[x][]=sons[x][]=size[x]=cnt[x]=value[x]=;
}
inline int get_w(int p){
return sons[f[p]][]==p;
}
inline void update(int p){
if(p){
size[p]=cnt[p];
if(sons[p][]) size[p]+=size[sons[p][]];
if(sons[p][]) size[p]+=size[sons[p][]];
}
}
inline void rotate(int x){ //旋转节点x
int fa=f[x],gfa=f[f[x]],ws=get_w(x);
sons[fa][ws]=sons[x][ws^]; //father与son
f[sons[fa][ws]]=fa;
f[fa]=x; //father与x
sons[x][ws^]=fa;
f[x]=gfa; //x与grandfather
if(gfa) sons[gfa][sons[gfa][]==fa]=x;
update(x);
update(fa);
}
inline void Splay(int x){ //将x旋到root
for(int fa;fa=f[x];rotate(x))
if(f[fa])
rotate(get_w(x)==get_w(fa)?fa:x); //若x,father,grandfather三个节点呈一条直线,就旋中间的节点
root=x;
}
void insert(int x){ //插入节点
if(!root){ //如果树为空
Size++;
f[Size]=sons[Size][]=sons[Size][]=;
size[Size]=cnt[Size]=;
value[Size]=x;
root=Size;
return;
}
int now=root,fa=;
while(){
if(value[now]==x){ //如果已有的节点值=x
cnt[now]++; //该节点数量+1
update(now);
update(fa);
Splay(now); //旋到root,维护平衡树
return;
}
fa=now;
now=sons[now][x>value[now]];
if(!now){ 如果旋到叶子节点,新开一个点
Size++;
sons[Size][]=sons[Size][]=;
f[Size]=fa;
size[Size]=cnt[Size]=;
value[Size]=x;
sons[fa][value[fa]<x]=Size;
update(fa);
Splay(Size);
return;
}
}
}
int find_num(int x){ //找大小顺序为x的节点的值
int now=root;
while(){
if(sons[now][]&&x<=size[sons[now][]]) now=sons[now][]; //左子树大小>x,则向左子树查询
else{
int temp=(sons[now][]?size[sons[now][]]:)+cnt[now];
if(x<=temp) return value[now]; //x包含在cnt[now]中
x-=temp;
now=sons[now][];
}
}
}
int find_rank(int x){ //查询值为x的点的大小编号
int now=root,ans=;
while(){
if(x<value[now]) now=sons[now][];
else{
ans+=sons[now][]?size[sons[now][]]:;
if(x==value[now]){
Splay(now);
return ans+;
}
ans+=cnt[now];
now=sons[now][];
}
}
}
inline int find_pre(){ //root的前驱即为左子树中最靠右的点
int now=sons[root][];
while(sons[now][]) now=sons[now][];
return now;
}
inline int find_suf(){
int now=sons[root][];
while(sons[now][]) now=sons[now][];
return now;
}
void delete_node(int x){ //删除节点x
find_rank(x); //将x旋上去
if(cnt[root]>){
cnt[root]--;
update(root);
return;
}
if(!sons[root][]&&!sons[root][]){
clear(root); root=; return;
}
if(!sons[root][]){
int last=root;
root=sons[root][];
f[root]=;
clear(last);
return;
}
if(!sons[root][]){
int last=root;
root=sons[root][];
f[root]=;
clear(last);
return;
}
int last=root,pre=find_pre(); //将前驱旋上去,此时x为pre的右儿子,直接删除即可(类似于链表)
Splay(pre);
sons[root][]=sons[last][];
f[sons[last][]]=root;
clear(last);
update(root);
}
int main()
{
n=read();
int opt,x;
while(n--){
opt=read(); x=read();
switch(opt){
case : insert(x); break;
case : delete_node(x); break;
case : printf("%d\n",find_rank(x)); break;
case : printf("%d\n",find_num(x)); break;
case : insert(x);printf("%d\n",value[find_pre()]);delete_node(x); break;
case : insert(x);printf("%d\n",value[find_suf()]);delete_node(x); break;
}
}
return ;
}
【洛谷P3369】 (模板)普通平衡树的更多相关文章
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 洛谷.3369.[模板]普通平衡树(Splay)
题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...
- 洛谷.3369.[模板]普通平衡树(fhq Treap)
题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- 洛谷.3391.[模板]文艺平衡树(Splay)
题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...
- 洛谷P3369 【模板】普通平衡树(Treap/SBT)
洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...
- 【洛谷P3369】【模板】普通平衡树题解
[洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...
- 洛谷P3369普通平衡树(Treap)
题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会
平衡树是什么东西想必我就不用说太多了吧. 百度百科: 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害.而第二天我调Splay的模板竟 ...
- 洛谷P3380 二逼平衡树
线段树+平衡树 我!又!被!卡!常!了! 以前的splay偷懒的删除找前驱后继的办法被卡了QAQ 放一个在洛谷开O2才能过的代码..我太菜了.. #include <bits/stdc++.h& ...
随机推荐
- filter get乱码 全站编码解决 包装模式
包装模式简介: package com.itheima.test; import java.io.BufferedReader; import java.io.IOException; import ...
- 牛客网Java刷题知识点之OSI七层参考模型 和 TCP/IP五层参考模型
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
- 【问题记录】 Linux 安装 apache 遇到的一些问题
以下为linux上安装apache时自己遇到的一些问题,记录在这,以后遇到时也会不定时更新... 一.安装Apache提示APR not found的解决办法 解决方法: 1. 网站 http://a ...
- 关于重定向printf出错 Error[Pe020]: identifier "FILE" is undefined 解决方案
IAR或者Keil用到重定向printf函数出现的错误解决方案 转发请注明出处,谢谢 原创:李剀 https://www.cnblogs.com/kevin-nancy/articles/105851 ...
- OpenGL Loading
什么是 OpenGL loading? OpenGL是一份API规范,并不是一个库.记住这点非常重要!它意味着每一个API背后的具体实现都依赖于你的GPU硬件.操作系统以及显卡驱动. OpenGL规范 ...
- VS中为什么不同的项目类型属性查看和设置的界面不一样
在VS中,存在ATL.MFC.Win32.CLR.常规等等各种工程模板,这些工程模板对应于开发不同类型的应用,比如要开发com,你应该选ATL:开发最原始的通过API代用操作系统的应用,应该用Win3 ...
- jqgrid 上移下移单元格
在表格中常常需要调整表格中数据的显示顺序,我用的是jqgrid,实现原理就是将表中的行数保存到数据库中,取数据时按行进行排序 1.上移,下移按钮 <a href="javascript ...
- node.js服务器端下载、上传文件
使用request 下载文件: 安装依赖: npm i requestsourceUrl下载源,targetUrl保存路径 async function downLoadFile(sourceUrl, ...
- stark——增删改页面
一.制作添加页面 1.前置准备 (1)修改增删改的视图函数名 class ModelStark(object): def add_view(self, request): return HttpRes ...
- linux环境下安装jdk(本文示例是jdk1.6.0_45)
第一步:创建一个文件夹安装jdk(虽说地址一般自定义,但是为了方便查找请按照笔者建议目录 ):/usr/java 将jdk-6u45-linux-x64.bin文件放到 /usr/java 文件夹 ...