今天的杭电多校打了之后,有一个题,我们有思路,但是却实现不了,之后看了题解发现需要用到动态树,然后,我太菜了,啥都不会(呜呜呜,猛男落泪)。然后去了解了一下发现,动态树需要前置技能splay,所以今天肝了一下,从晚上9点开始写代码,一直到一点才A掉题。

闲话说完,现在说一下splay的一些做法。
因为这里条件有限,所以不会太详细,大家可以看一下这个blog
这篇博客只写一些博主的理解。

模板题:P3369
接下来介绍一下splay的操作:
旋转节点:
splay的旋转,就是保持二叉树的特性将节点上旋,
因为没图,大家可以去上面的链接上看。
个人认为splay操作是很玄学的操作,它的做法是通过一些旋转方式,让节点变为根节点,并且让查找树变得比较平衡。但是我认为这个操作和无旋treap的key的随机值一样,都是玄学的(其实是我不会证明,嘤嘤嘤)。
唔,剩下的就在代码里面了叭,(额,因为现在有点晚了,剩下的明天再补)。
代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
//mt19937 rnd(time(NULL));
#define pp pair<int,int>
#define ull unsigned long long
#define ls root<<1
#define rs root<<1|1
//#define int long long
typedef long long ll;
const int inf = 1e9;
const int NINF = 0xc0c0c0c0;
const int maxn = 1e5+7;
const int bas=maxn/2;
const int Maxn = 1e7+7;
const double eps=1e-6;
const int mod=1000000007;
struct Splay{int num,val,size,recy,son[2];void init(){num=val=size=recy=son[0]=son[1]=0;}
}t[maxn];
int f[maxn],root,cnt;
void clear(int x){t[x].init();
}
int get(int x){//得到父子关系return t[f[x]].son[1]==x;
}
void update(int x){//更新节点if(x){t[x].size=t[x].recy;if(int a=t[x].son[0])t[x].size+=t[a].size;if(int a=t[x].son[1])t[x].size+=t[a].size;}
}
void connext(int x,int y,int z){//x连到y下面,关系为zif(x)f[x]=y;if(y)t[y].son[z]=x;
}
void rotate(int x){//上旋int fa=f[x],ffa=f[fa],m=get(x),n=get(fa);connext(t[x].son[m^1],fa,m);connext(fa,x,m^1);connext(x,ffa,n);update(fa);update(x);
}
void splay(int x){//splay/** 节点上旋,核心操作*/for(int fa;fa=f[x];rotate(x)){if(f[fa])rotate(get(x)==get(fa)?fa:x);//printf("%d\n",fa);}root=x;
}
void insert(int x){//增加节点/** 如果根节点为空,增加根节点*/if(!root){root=++cnt;t[root].val=x;t[root].size=t[root].recy=1;t[root].son[0]=t[root].son[1]=0;return;}int now=root,fa=0;/** 在二叉树中查找合适的位置插入x*/while(1){/** 如果之前存在值为x的节点,那么增加出现次数即可*/if(t[now].val==x){t[now].recy++;update(now),update(fa);splay(now);return ;}/** 继续用二叉查找树的方式去查找* 如果遇到空节点了,那么就创造节点*/fa=now,now=t[now].son[x>t[now].val];if(!now){++cnt;t[cnt].val=x;t[cnt].size=t[cnt].recy=1;f[cnt]=fa;t[fa].son[x>t[fa].val]=cnt;update(fa);splay(cnt);return;}}
}
int find(int x){//找到值为x的排名int now=root,ans=0;while(1){/** 如果x在左子树中,继续查找左子树*/if(x<t[now].val){now=t[now].son[0];continue;}/** 不在左子树,ans加上左子树的个数*/ans+=t[t[now].son[0]].size;/** 是否是目前子树的根节点*/if(x==t[now].val){splay(now);return ans+1;}/** 在右子树中,加上目前子树的根节点的值,再查找右子树*/ans+=t[now].recy;now=t[now].son[1];}
}
int rk(int x){//找排名为x的值int now=root;while(1){if(t[now].son[0] && x<=t[t[now].son[0]].size){/** 如果在左子树种,那么直接在左子树中查找*/now=t[now].son[0];continue;}/** 第x大的不在左子树里*///如果左子树存在,x-=左子树的个数if(t[now].son[0]) x-=t[t[now].son[0]].size;//是否可能是目前子树的根节点if(x<=t[now].recy){splay(now);return t[now].val;}x-=t[now].recy;now=t[now].son[1];}
}
int pre(){//前驱/** 做法:先将我们要查找的节点变为根节点,然后找左子树的最大值就可以了。*/int now=t[root].son[0];while(t[now].son[1])now=t[now].son[1];return now;
}
int nxt(){//后继/** 做法:先将我们要查找的节点变为根节点,然后找右子树的最小值就可以了*/int now=t[root].son[1];while(t[now].son[0])now=t[now].son[0];return now;
}
void del(int x){//删除节点int no_use=find(x);if(t[root].recy>1){//第一种情况,recy值大于1 这个时候recy--t[root].recy--;update(root);return ;}if(!t[root].son[0] && !t[root].son[1]){//只存在根节点,并且根节点的个数为1clear(root);root=0;return ;}if(!t[root].son[0]){//不存在左根,那么根变为右子树int tmp=root;f[root=t[root].son[1]]=0;clear(tmp);return ;}if(!t[root].son[1]){//不存在右子树,根节点变为左子树int tmp=root;f[root=t[root].son[0]]=0;clear(tmp);return;}/*左右子树都存在。那么将左子树的最大值变为根,然后将右子树变为根节点的右子树就可以了因为是二叉查找树,所以如果令左子树的最大值变为根,那么根节点的右子树为空因为其他值都比这个值小*/int tmp=root,left=pre();splay(left);connext(t[tmp].son[1],root,1);clear(tmp);update(root);
}
signed main(){#ifndef ONLINE_JUDGEfreopen("in.in","r",stdin);//freopen("out.out","w",stdout);
#endifint n;scanf("%d",&n);for(int i=1;i<=n;i++){int op,x;scanf("%d%d",&op,&x);switch(op){case 1://puts("case1");insert(x);break;case 2:del(x);break;case 3:printf("%d\n",find(x));break;case 4:printf("%d\n",rk(x));break;case 5:insert(x);printf("%d\n",t[pre()].val);del(x);break;case 6:insert(x);printf("%d\n",t[nxt()].val);del(x);break;}}
}

luogu P3369(Splay)相关推荐

  1. [学习笔记] 伸展树splay详解+全套模板+例题[Luogu P3369 【模板】普通平衡树]

    文章目录 引入概念 全套模板 变量声明 update ==rotate旋转== splay操作 insert插入 delete删除 查找x的位置 查找第k大 前驱/后继 极小值-inf和极大值inf的 ...

  2. Luogu P3165 Splay区间翻转

    脑残记录: 这周末2天只做了一道平衡树题目(2天被一道题限住),发现自己的很多问题, 学了算法及其性质 但是总是做不出来题目,很难利用学过的性质, 同样这种情况再次发生在今天 没有运用的能力,思维太差 ...

  3. fhq treap ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : LibreOJ #104. 普通平衡树 #include <cstdio> #include <iostream> #include <algorithm ...

  4. 【洛谷P3369】 (模板)普通平衡树

    https://www.luogu.org/problemnew/show/P3369 Splay模板 1 #include<iostream> 2 #include<cstdio& ...

  5. 平衡树【Splay树】学习小记

    简介 平衡树,顾名思义,平衡的搜索二叉树. 常见的平衡树都能将树的深度保持在 lg ⁡ n \lg_n lgn​ 的级别内,防止退化成链. 一些平衡树可以通过旋转.分裂.合并等操作完成更加高级的.二叉 ...

  6. C++ __gnu_pbds(平板电视)超详细教程(C++内置的平衡树,字典树,hash)

    整理的算法模板合集: ACM模板 目录 一.平衡树 例题:luogu P3369 [模板]普通平衡树 1. `rb_tree_tag`版 2. `splay_tree_tag`版 功能不够?自己添加! ...

  7. 快速入门Treap(代码实现)

    学习数据结构对我来说真的相当困难,网上讲\(Treap\)的我也看不太懂,前前后后花了大概六天才把\(Treap\)学会.为了避免再次忘记,这里我整理一下\(Treap\)的基础知识和模板. 阅读此文 ...

  8. 浅谈 Fhq-Treap

    问题引入:Luogu P3369 普通平衡树 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入 x x x 数 删除 x x x 数(若有多个相同的数,因只删除一个) ...

  9. BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)

    BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay) 手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.ne ...

  10. luogu P2584 [ZJOI2006]GameZ游戏排名系统 Splay

    luogu P2584 [ZJOI2006]GameZ游戏排名系统 Splay 实在不想调了QAQ... Code: #include <cstdio> #include <algo ...

最新文章

  1. WPF中为Grid增加边框
  2. python乘法口诀表-用python打印99乘法口诀表
  3. linux18.04下安装的jdk11.0.2
  4. Windows环境 和 Linux环境下搭建Qt开发环境
  5. js 获取元素,同级元素下的子元素总结
  6. java applet 换行_Java复习题
  7. maven 添加本地库
  8. 飞流直下三千尺的acd看图软件下载
  9. ubuntu查看进程和结束进程
  10. 利用 Erdas 软件将矿区拐点坐标转换为经纬度坐标
  11. 常见的非关系型数据库有哪些
  12. 【优化布局】基于粒子群算法求解带出入点的车间布局优化问题附matlab代码
  13. 高精度整数算法总结,尤其是乘法,面向小白版
  14. 保存一个免费的在线的图片转换工具网站,支持BMP,JPG,IOC,PNG和GIF
  15. 28岁学Java晚不晚?快30学java还来得及吗?
  16. Neuron:自动优化TMS线圈放置,实现个性化靶向功能网络刺激
  17. 最全最详细!请收下这份电路反馈基础知识秘
  18. 单相桥式全控整流电路
  19. 武汉长江大桥(游走武汉)
  20. LeetCode-环形链表|+环形链表||

热门文章

  1. 阿尔法营任务黑客机器人游戏答案
  2. 科技的终极目标是什么
  3. 计算机三种桌面图标,例举win7电脑桌面图标排列方式
  4. 【C++OJ多重继承与虚拟继承】商旅信用卡(多重继承)
  5. java太阳系论文摘要_毕业论文摘要
  6. 现身说法:37 岁老码农找工作
  7. 深度解析 intern 方法
  8. 孙子兵法始计篇读后感&心得(下)
  9. 【IoT】产品经理:人性洞察的底层逻辑
  10. SLE12 Server 在线安装MySQL Server