【洛谷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& ...
随机推荐
- 一个优秀的app应该考虑的问题
带着团队做了3个app,需求是客户决定的,甚至连进度都不是项目经理可以控制的(譬如说一个app要在6周内,3个人完成).现在的状态是基本上没有用户量,当然原因是多方面的,下面说一说我认为app设计的原 ...
- 1分钟搭建极简mock server
1.无聊的背景.起源: 如今的业务系统越来越复杂庞大,各个功能直接的调用也是多如牛毛,但如果在联调的时候,恰好被调的接口正在开发,怎么办?傻傻的等么,不存在的!这时会搭建一些server来进行mock ...
- Spring Data JPA简单使用
用Spring Data JPA操作数据库 这份教程教你用Spring Data JPA从关系数据库mysql中存储和提取数据.总结来自https://spring.io/guides/gs/acce ...
- java中try-catch-finally中的return语句
在try-catch-finally语句中使用return语句遇到了一些疑问 代码一: static int intc(){ int x =0; try{ x=1; return x; }finall ...
- PAT 1024 Palindromic Number
#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> ...
- 使用jquery去掉时光轴头尾部的线条
一.前言:以前做类似时光轴的结构,几乎都是一条灰色线飞流直下,没有尽头.今天这个线条是从第一个圆点到最后一个圆点,那么问题来了,内容的高度还不是固定的,线条的长度怎么确定?怎么就能刚刚好从第一个点到最 ...
- Oracle数据库错误消息
Oracle数据库错误消息 导出错误消息 l EXP-00000导出终止失败 原因:导出时产生Oracle错误. 操作:检查相应的Oracle错误消息. l EXP-00001数据域被截断 - 列长度 ...
- 使用weinre调试Web应用及PhoneGap应用
Web开发者经常使用Firefox的firebug或者Chrome的开发人员工具进行Web调试,包括针对JavaScript,DOM元素和CSS样式的调试.但是,当我们期望为移动Web站点或应用进行调 ...
- Anaconda教程
python虚拟环境 当安装新的外部python包时,为了保证原版python的纯净,避免其他项目调试时出现错误,可使用Anaconda创建虚拟python进行调试和操作 创建新的虚拟环境(Win ...
- CCF201803-1 跳一跳
试题编号: 201803-1 试题名称: 跳一跳 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱. 简化后的跳一跳规则如下: ...