题目

\(\rm splay\)水平太差,于是得手玩一下才能发现规律

首先插入一个数,其肯定会成为其前驱的右儿子或者是后继的左儿子,进一步手玩发现前驱的右儿子或者是后继的左儿子一定只有一个是空的,我们找到这个空位置插入就好了

于是我们需要一个\(\rm std::set\)来查找前驱后继,同时我们还需要维护每个点的左右儿子和父亲

继续手玩发现由于只有对最大值和最小值的操作,所以对\(\rm splay\)的结构影响很小,于是这个过程中也能维护每个节点的父亲的左右儿子

深度看起来不能用几个数组来维护了,于是我们直接用lct维护这棵树的形态,深度查一下到当前根的路径上的节点个数即可

代码

#include<bits/stdc++.h>
#define re register
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
struct LinkCutTree {
int fa[maxn],ch[maxn][2],sz[maxn],rev[maxn];
int st[maxn],top;
inline int nrt(int x) {return ch[fa[x]][1]==x||ch[fa[x]][0]==x;}
inline void pushup(int x) {sz[x]=sz[ch[x][0]]+1+sz[ch[x][1]];}
inline void rotate(int x) {
int y=fa[x],z=fa[y],w=ch[y][1]==x,k=ch[x][w^1];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[x][w^1]=y,ch[y][w]=k;
pushup(y),pushup(x);fa[k]=y,fa[y]=x,fa[x]=z;
}
inline void work(int x) {rev[x]^=1;std::swap(ch[x][0],ch[x][1]);}
inline void pushdown(int x) {
if(!rev[x]) return;rev[x]=0;
if(ch[x][0]) work(ch[x][0]);
if(ch[x][1]) work(ch[x][1]);
}
inline void splay(int x) {
int y=x;top=0;
st[++top]=x;
while(nrt(y)) y=fa[y],st[++top]=y;
while(top) pushdown(st[top--]);
while(nrt(x)) {
int y=fa[x];
if(nrt(y)) rotate((ch[y][1]==x)^(ch[fa[y]][1]==y)?x:y);
rotate(x);
}
}
inline void access(int x) {
for(re int y=0;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline void mrt(int x) {
access(x);splay(x);work(x);
}
inline void link(int x,int y) {
mrt(x);fa[x]=y;
}
inline void split(int x,int y) {
mrt(x),access(y),splay(y);
}
inline void cut(int x,int y) {
split(x,y);fa[x]=ch[y][0]=0;pushup(y);
}
inline int dis(int x,int y) {
split(x,y);return sz[y];
}
}lct;
struct RBT {
std::set<int> s;
#define It std::set<int>::iterator
inline int pre(int x) {
It it=s.find(x);
if(it==s.begin()) return 0;
--it;return *it;
}
inline int nxt(int x) {
It it=s.find(x);++it;
if(it==s.end()) return 0;
return *it;
}
inline void del(int x) {s.erase(x);}
inline void ins(int x) {s.insert(x);}
inline int Gmin() {It it=s.begin();return *it;}
inline int Gmax() {It it=s.end();--it;return *it;}
inline int empty() {return s.empty();}
}s;
int n,m,rt;
int a[maxn],b[maxn],son[maxn][2],op[maxn],fa[maxn];
inline int find(int x) {
int l=1,r=n;
while(l<=r) {
int mid=l+r>>1;
if(b[mid]==x) return mid;
if(b[mid]<x) l=mid+1;else r=mid-1;
}
return 0;
}
inline int ins(int x) {
s.ins(x);
if(!rt) {fa[x]=0;rt=x;return 1;}
int Pre=s.pre(x);
if(Pre&&!son[Pre][1])
lct.link(Pre,x),son[Pre][1]=x,fa[x]=Pre;
else {
int Nxt=s.nxt(x);
if(Nxt&&!son[Nxt][0])
lct.link(Nxt,x),son[Nxt][0]=x,fa[x]=Nxt;
}
return lct.dis(rt,x);
}
inline void move_min() {
int x=s.Gmin();
printf("%d\n",lct.dis(x,rt));
if(x==rt) return;
lct.cut(fa[x],x);
if(son[x][1]) lct.cut(x,son[x][1]);
lct.link(x,rt);
if(son[x][1]) lct.link(fa[x],son[x][1]);
fa[son[x][1]]=fa[x];fa[rt]=x;
son[fa[x]][0]=son[x][1];
son[x][1]=rt;fa[x]=0;rt=x;
}
inline void move_max() {
int x=s.Gmax();
printf("%d\n",lct.dis(x,rt));
if(x==rt) return;
lct.cut(fa[x],x);
if(son[x][0]) lct.cut(x,son[x][0]);
lct.link(rt,x);
if(son[x][0]) lct.link(fa[x],son[x][0]);
fa[son[x][0]]=fa[x],fa[rt]=x;
son[fa[x]][1]=son[x][0];
son[x][0]=rt,fa[x]=0;rt=x;
}
inline void pop(int x) {
if(son[x][0]) lct.cut(x,son[x][0]),rt=son[x][0];
if(son[x][1]) lct.cut(x,son[x][1]),rt=son[x][1];
son[x][0]=son[x][1]=fa[x]=0;
s.del(x);if(s.empty()) rt=0;
}
int main() {
m=read();
for(re int i=1;i<=m;i++) {
op[i]=read();
if(op[i]==1) a[i]=read(),b[++n]=a[i];
}
std::sort(b+1,b+n+1);
for(re int i=1;i<=m;i++) {
if(op[i]==1) printf("%d\n",ins(find(a[i])));
if(op[i]==2) move_min();
if(op[i]==3) move_max();
if(op[i]==4) move_min(),pop(rt);
if(op[i]==5) move_max(),pop(rt);
}
return 0;
}

[AH2017/HNOI2017]单旋的更多相关文章

  1. P3721 [AH2017/HNOI2017]单旋

    题目:https://www.luogu.org/problemnew/show/P3721 手玩一下即可AC此题. 结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它 ...

  2. 洛谷 P3721 - [AH2017/HNOI2017]单旋(LCT)

    洛谷题面传送门 终于调出来这道题了,写篇题解( 首先碰到这样的题我们肯定要考虑每种操作会对树的形态产生怎样的影响: 插入操作:对于 BST 有一个性质是,当你插入一个节点时,其在 BST 上的父亲肯定 ...

  3. luogu P3721 [AH2017/HNOI2017]单旋

    传送门 \(Spaly:\)??? 考虑在暴力模拟的基础上优化 如果要插入一个数,那么根据二叉查找树的性质,这个点一定插在他的前驱的右子树或者是后继的左子树,可以利用set维护当前树里面的数,方便查找 ...

  4. 洛谷P3721 [AH2017/HNOI2017]单旋(线段树 set spaly)

    题意 题目链接 Sol 这题好毒瘤啊.. 首先要观察到几个性质: 将最小值旋转到根相当于把右子树变为祖先的左子树,然后将原来的根变为当前最小值 上述操作对深度的影响相当于右子树不变,其他的位置-1 然 ...

  5. [AH2017/HNOI2017] 单旋 - Splay

    Splay 暴力维护节点信息即可 #include<iostream> #include<cstdio> #include<cstring> #include< ...

  6. bzoj 4825: [Hnoi2017]单旋 [lct]

    4825: [Hnoi2017]单旋 题意:有趣的spaly hnoi2017刚出来我就去做,当时这题作死用了ett,调了5节课没做出来然后发现好像直接用lct就行了然后弃掉了... md用lct不知 ...

  7. 【LG3721】[HNOI2017]单旋

    [LG3721][HNOI2017]单旋 题面 洛谷 题解 20pts 直接模拟\(spaly\)的过程即可. 100pts 可以发现单旋最大.最小值到根,手玩是有显然规律的,发现只需要几次\(lin ...

  8. 4825: [Hnoi2017]单旋

    4825: [Hnoi2017]单旋 链接 分析: 以后采取更保险的方式写代码!!!81行本来以为不特判也可以,然后就总是比答案大1,甚至出现负数,调啊调啊调啊调~~~ 只会旋转最大值和最小值,以最小 ...

  9. [BZOJ4825][HNOI2017]单旋(线段树+Splay)

    4825: [Hnoi2017]单旋 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 667  Solved: 342[Submit][Status][ ...

随机推荐

  1. 关于命令ride.py打不开RF,而是打开pycharm编辑器问题解决思路

    自从用RF工具做自动化测试以来,碰到过三次标题中的问题.头两次问别人解决了,第三次就自己动手解决,并记录下来. 第一次碰到这个问题,以为问题很小,没有放在心上,同事帮忙弄出来了. 别人帮忙弄的,记忆力 ...

  2. SAS市场研究应用介绍:组合/联合分析

    SAS市场研究应用介绍:组合/联合分析 一 SAS市场研究模块介绍 市场研究是指研究组织(企业)与客户.公众三者关系的规律的过程,是市场营销领域中的一个重要元素.它把消费者.客户.公众和营销者通过信息 ...

  3. 命令行启动tomcat

    windows下进入CMD启动.window+r打开命令窗口具体步骤:1:在命令行中输入Tomcat安装的磁盘:E:2:进入Tomcat的主安装目录:cd Tomcat3:进入bin文件夹:cd bi ...

  4. Django框架(五)—— 虚拟环境搭建

    目录 Django虚拟环境搭建 Django虚拟环境搭建 一.为什么要用虚拟环境 公司以前开发的项目是在Django1.5的基础上开发的,先要需要基于Django2.0开发一套项目.这样不能卸载原有版 ...

  5. 设计模式四人帮(GOF)是什么?

    1994年,有四位作者:Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides发表了一本题为<设计模式 - 可重用的面向对象软件元素>的 ...

  6. MyEclipse中最常用的快捷键大全

    1. [ALT+/]    此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ALT+/]快捷键带来的好处吧. 2. [C ...

  7. 教你如何有效防止DDos攻击?

    DDos又称分布式拒绝服务,DDos是利用大量合理的请求造成资源过载,导致服务不可用.就比如一个餐馆总共有100个座位,突然有一天某个商家恶意竞争,雇佣了200个人来到这个餐馆坐着不吃不喝,门口还排着 ...

  8. 我要多开梦幻手游PC端(梦幻手游PC端多开的简单分析及实现办法)(二)

    上一篇,多开方法,适用于一年前的版本 http://www.cnblogs.com/suanguade/p/5646776.html 前言: 一转眼一年过去了,日子越来越无聊了,于是,准备再玩一玩梦幻 ...

  9. linux常用命令-3文件与目录相关命令

    cd .. #返回上一级目录 cd ../.. #返回上两级目录 cd - #返回上次所在目录 cp file1 file2 #将file1复制为file2 cp -a dir1 dir2 #复制一个 ...

  10. Python全栈开发:RabbitMQ/Redis/Memcache/SQLAlchemy

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...