Description

H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构。伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能。有一天,邪恶的“卡”带着他的邪恶的“常数”来企图毁灭 H 国。“卡”给 H 国的人洗脑说,splay 如果写成单旋的,将会更快。“卡”称“单旋 splay”为“spaly”。虽说他说的很没道理,但还是有 H 国的人相信了,小 H 就是其中之一,spaly 马上成为他的信仰。 而 H 国的国王,自然不允许这样的风气蔓延,国王构造了一组数据,数据由 m 个操作构成,他知道这样的数据肯定打垮 spaly,但是国王还有很多很多其他的事情要做,所以统计每个操作所需要的实际代价的任务就交给你啦。
数据中的操作分为五种:
1. 插入操作:向当前非空 spaly 中插入一个关键码为 key 的新孤立节点。插入方法为,先让 key 和根比较,如果 key 比根小,则往左子树走,否则往右子树走,如此反复,直到某个时刻,key 比当前子树根 x 小,而 x 的左子树为空,那就让 key 成为 x 的左孩子; 或者 key 比当前子树根 x 大,而 x 的右子树为空,那就让 key 成为 x 的右孩子。该操作的代价为:插入后,key 的深度。特别地,若树为空,则直接让新节点成为一个单个节点的树。(各节点关键码互不相等。对于“深度”的解释见末尾对 spaly 的描述)。
2. 单旋最小值:将 spaly 中关键码最小的元素 xmin 单旋到根。操作代价为:单旋前 xmin 的深度。(对于单旋操作的解释见末尾对 spaly 的描述)。
3. 单旋最大值:将 spaly 中关键码最大的元素 xmax 单旋到根。操作代价为:单旋前 xmax 的深度。
4. 单旋删除最小值:先执行 2 号操作,然后把根删除。由于 2 号操作之后,根没有左子树,所以直接切断根和右子树的联系即可(具体见样例解释)。 操作代价同 2 号操 作。
5. 单旋删除最大值:先执行 3 号操作,然后把根删除。 操作代价同 3 号操作。
对于不是 H 国的人,你可能需要了解一些 spaly 的知识,才能完成国王的任务:
a. spaly 是一棵二叉树,满足对于任意一个节点 x,它如果有左孩子 lx,那么 lx 的关键码小于 x 的关键码。如果有右孩子 rx,那么 rx 的关键码大于 x 的关键码。
b. 一个节点在 spaly 的深度定义为:从根节点到该节点的路径上一共有多少个节点(包括自己)。
c. 单旋操作是对于一棵树上的节点 x 来说的。一开始,设 f 为 x 在树上的父亲。如果 x 为 f 的左孩子,那么执行 zig(x) 操作(如上图中,左边的树经过 zig(x) 变为了右边的树),否则执行 zag(x) 操作(在上图中,将右边的树经过 zag(f) 就变成了左边的树)。每当执 行一次 zig(x) 或者 zag(x),x 的深度减小 1,如此反复,直到 x 为根。总之,单旋 x 就是通过反复执行 zig 和 zag 将 x 变为根。

Input

第一行单独一个正整数 m。
接下来 m 行,每行描述一个操作:首先是一个操作编号 c∈[1,5],即问题描述中给出的五种操作中的编号,若 c = 1,则再输入一个非负整数 key,表示新插入节点的关键码。
1≤m≤10^5,1≤key≤10^9
所有出现的关键码互不相同。任何一个非插入操作,一定保证树非空。在未执行任何操作之前,树为空

Output

输出共 m 行,每行一个整数,第 i 行对应第 i 个输入的操作的代价。

Sample Input

5
1 2
1 1
1 3
4
5

Sample Output

1
2
2
2
2

正解:$link-cut \ tree+set$

这题我能说什么。。考场上没想到,然而考后就想出来了。。

其实这题是一道大水题吧。。其实连$LCT$都不要用,直接线段树维护就行了。。

我们可以观察得到:插入结点时一定是插到它的前驱或后继中深度更深的那个下面。

单旋最值其实就是把最值抽出来,与原来的根相连,然后再把它的子树与它原来的父亲相连。删除操作类似,还简单一些。。

然后我们直接用$LCT$维护$spaly$。插入,单旋,删除的时候各种$link$,$cut$就行了,顺便再开两个数组维护一下原树的父子关系。

同时我们要查询前驱,后继,最小值,最大值,这个用$set$就能很方便地解决。

每次查询深度,就是$makeroot$一下树根,然后$access$并$splay$当前点,直接查询$splay$中子树大小就行了。

注意细节:如果单旋的时候这个点已经是根就不要$link$,$cut$了。这个地方坑了我好久。。

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (100010)
#define ls (x<<1)
#define rs (x<<1|1)
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; set <int> tr;
set <int>::iterator r; struct data{ int c,k; }q[N]; int hsh[N],rev[N],sz[N],st[N],fa[N],ch[N][],f[N],c[N][],m,rt,cnt,tot; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il int isroot(RG int x){
return ch[fa[x]][]!=x && ch[fa[x]][]!=x;
} il void pushdown(RG int x){
rev[x]=,rev[ch[x][]]^=,rev[ch[x][]]^=;
swap(ch[x][],ch[x][]); return;
} il void pushup(RG int x){
sz[x]=sz[ch[x][]]+sz[ch[x][]]+; return;
} il void rotate(RG int x){
RG int y=fa[x],z=fa[y],k=ch[y][]==x;
if (!isroot(y)) ch[z][ch[z][]==y]=x;
fa[x]=z,ch[y][k^]=ch[x][k],fa[ch[x][k]]=y;
ch[x][k]=y,fa[y]=x,pushup(y),pushup(x); return;
} il void splay(RG int x){
RG int top=; st[++top]=x;
for (RG int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
for (RG int i=top;i;--i) if (rev[st[i]]) pushdown(st[i]);
while (!isroot(x)){
RG int y=fa[x],z=fa[y];
if (!isroot(y)){
if ((ch[z][]==y)^(ch[y][]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
return;
} il void access(RG int x){
RG int t=;
while (x){
splay(x),ch[x][]=t;
pushup(x),t=x,x=fa[x];
}
return;
} il void makeroot(RG int x){
access(x),splay(x),rev[x]^=; return;
} il void link(RG int x,RG int y){
if (!x || !y || x==y) return;
makeroot(x),fa[x]=y; return;
} il void cut(RG int x,RG int y){
if (!x || !y || x==y) return;
makeroot(x),access(y),splay(y);
fa[x]=ch[y][]=,pushup(y); return;
} il int query(RG int x){
makeroot(rt),access(x),splay(x);
return sz[x];
} il void update1(RG int x,RG int k){
RG int y=f[x],z=c[x][k];
c[x][k]=rt,f[rt]=x,f[x]=;
c[y][k^]=z,f[z]=y; return;
} il void update2(RG int x,RG int k){
RG int y=f[x],z=c[x][k]; if (x==rt) rt=z;
c[y][k^]=z,f[z]=y,c[x][k]=f[x]=; return;
} il void work(){
m=gi(),tr.insert(-inf),tr.insert(inf);
for (RG int i=;i<=m;++i){
q[i].c=gi(),sz[i]=;
if (q[i].c==) q[i].k=gi(),hsh[++tot]=q[i].k;
}
sort(hsh+,hsh+tot+),tot=unique(hsh+,hsh+tot+)-hsh-;
for (RG int i=;i<=m;++i){
if (q[i].c==){
q[i].k=lower_bound(hsh+,hsh+tot+,q[i].k)-hsh;
if (!cnt) tr.insert(rt=q[i].k),++cnt,puts(""); else{
r=tr.upper_bound(q[i].k); RG int nxt=*r,x=,d=,k; --r; RG int pre=*r;
if (pre!=-inf){ k=query(pre); if (d<k) x=pre,d=k; }
if (nxt!=inf){ k=query(nxt); if (d<k) x=nxt,d=k; }
f[q[i].k]=x,c[x][x<q[i].k]=q[i].k,link(x,q[i].k);
++cnt,tr.insert(q[i].k),printf("%d\n",d+);
}
}
if (q[i].c==){
if (cnt==) puts(""); else{
r=tr.begin(),++r; RG int x=*r,y=f[x],z=c[x][],k=query(x);
if (x!=rt) cut(x,y),cut(x,z),link(x,rt),link(y,z),update1(x,),rt=x;
printf("%d\n",k);
}
}
if (q[i].c==){
if (cnt==) puts(""); else{
r=tr.end(),--r,--r; RG int x=*r,y=f[x],z=c[x][],k=query(x);
if (x!=rt) cut(x,y),cut(x,z),link(x,rt),link(y,z),update1(x,),rt=x;
printf("%d\n",k);
}
}
if (q[i].c==){
if (cnt==) puts(""),tr.erase(tr.find(rt)),rt=,--cnt; else{
r=tr.begin(),++r; RG int x=*r,y=f[x],z=c[x][],k=query(x);
tr.erase(tr.find(x)),--cnt,cut(x,y),cut(x,z),link(y,z);
update2(x,),printf("%d\n",k);
}
}
if (q[i].c==){
if (cnt==) puts(""),tr.erase(tr.find(rt)),rt=,--cnt; else{
r=tr.end(),--r,--r; RG int x=*r,y=f[x],z=c[x][],k=query(x);
tr.erase(tr.find(x)),--cnt,cut(x,y),cut(x,z),link(y,z);
update2(x,),printf("%d\n",k);
}
}
}
return;
} int main(){
File("splay");
work();
return ;
}

bzoj4825 [Hnoi2017]单旋的更多相关文章

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

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

  2. BZOJ4825: [Hnoi2017]单旋(Splay)

    题面 传送门 题解 调了好几个小时--指针太难写了-- 因为只单旋最值,我们以单旋\(\min\)为例,那么\(\min\)是没有左子树的,而它旋到根之后,它的深度变为\(1\),它的右子树里所有节点 ...

  3. BZOJ4825 [Hnoi2017]单旋 【线段树】

    题目链接 BZOJ4825 题解 手模一下操作,会发现一些很优美的性质: 每次旋到根,只有其子树深度不变,剩余点深度\(+1\) 每次旋到根,[最小值为例]右儿子接到其父亲的左儿子,其余点形态不改变, ...

  4. [BZOJ4825][HNOI2017]单旋spaly

    BZOJ Luogu 题目太长了,就不放了. 题解 首先声明一点,无论是splay还是spaly,插入一个新的元素,都要rotate到根!所以说题目也算是给了一个错误示范吧. 我们发现把最值旋转到根并 ...

  5. 【BZOJ4825】[Hnoi2017]单旋 线段树+set

    [BZOJ4825][Hnoi2017]单旋 Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能 ...

  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]单旋 线段树+STL-set

    题目描述 H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天 ...

随机推荐

  1. [lua] 游戏客户端逻辑使用lua协程

    我们的游戏有这样一种情景:客户端中角色需要用到一些公会的数据,但服务器不会在玩家(创角后)一进入到游戏里就推送给玩家,而是需要客户端自己在需要的时候向服务器请求公会的数据,之前的实现就是在请求消息的时 ...

  2. ORM-Dapper学习<一>

    ORM 框架简介 对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的.面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关 ...

  3. JavaWeb之Filter、Listener

    昨天和大家介绍了一下JSON的用法,其实JSON中主要是用来和数据库交互数据的.今天给大家讲解的是Filter和Listener的用法. 一.Listenner监听器 1.1.定义 Javaweb中的 ...

  4. Android使用Aspectj

    使用AspectJ 集成步骤: 1.AS配置Aspectj环境 2.配置使用ajc编译 4.定义注解 5.配置规则 6.使用 7.注意事项 AS配置Aspectj环境.Aspect目前最新版本为 1. ...

  5. Java标准注释配置

    eclipse中java文件头注释格式设置 windows->preferences->java->Code Templates->comments->Type-> ...

  6. shiro权限控制

    1.1  简介 Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Securi ...

  7. vertical-align用法

    父元素下面有两个子元素,第一个子元素设置display:inline-block,第二个子元素设置display:inline-block, vertical-align:top这样两个元素就能顶部对 ...

  8. js数组的几个练习题

    第一次在博客园写文章,之前一直自己做记录.现在前端工作两年了,对前端整体技术有较清晰的了解.项目用了vue,react之类的写,如今打算从基础开始,慢慢深入了解原生的JS.这几天清明节,玩的嗨皮,最后 ...

  9. 简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ解析

    对于目前大多的.NET项目,其实使用的技术栈都是差不多,估计现在很少用控件开发项目的了,毕竟一大堆问题.对.NET的项目,目前比较适合的架构ASP.NET MVC,ASP.NET WebAPI,ORM ...

  10. 玩转 SSH 目录

    在做一个新的项目的时候,需要重新搭建一个项目. 于是趁着这个机会把之前学的几个框架的搭建都写一写,整理一下,同时也可以给大家一些参考.何乐而不为叻. 在这个系列中, 我将使用 IntelJ IDEA ...