[HNOI 2017]单旋
Description

Input
Output
Sample Input
1 2
1 1
1 3
4
5
Sample Output
1
2
2
2
2
题解
参考了PIPIBoss的做法。
我们手玩一下单旋,发现其如果只改变最大最小值时,主要的性质就是整棵$splay$的形态不会发生很大的改变。
例如旋最小值到根,其实就相当于将最小值的节点取出来,最小值的右儿子连向最小值的父亲。接着再把最小值对应的节点接在原来的根的父亲上。
最大值同理。那么就可以用$LCT$维护了。
对于插入操作,很显然的是这个新插入的节点肯定接向其前驱的右儿子或后继的左儿子。另外,这两个儿子肯定有一个是空的,有一个不空。另外,不空的儿子就是前驱和后继两个中深度较深节点的儿子。
我们将权值离散,找前驱后继就交给$STL-set$,另外还要额外开数组来记录原来$splay$树的形态。
//It is made by Awson on 2017.12.27
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define LD long double
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 1e5;
const int INF = ~0u>>; int m, a[N+], top;
struct Opt {
int opt, x;
}q[N+];
struct Link_Cut_Tree {
int ch[N+][], pre[N+], size[N+], isrt[N+], rev[N+];
set<int>S;
int f[N+], c[N+][], root;
Link_Cut_Tree () {
for (int i = ; i <= N; i++) size[i] = isrt[i] = ;
S.insert(-INF), S.insert(INF);
}
void pushdown(int o) {
if (!o || !rev[o]) return;
int ls = ch[o][], rs = ch[o][];
swap(ch[ls][], ch[ls][]), swap(ch[rs][], ch[rs][]);
rev[ls] ^= , rev[rs] ^= , rev[o] = ;
}
void push(int o) {
if (!isrt[o]) push(pre[o]);
pushdown(o);
}
void pushup(int o) {
if (!o) return;
size[o] = size[ch[o][]]+size[ch[o][]]+;
}
void rotate(int o, int kind) {
int p = pre[o];
ch[p][!kind] = ch[o][kind], pre[ch[o][kind]] = p;
if (isrt[p]) isrt[o] = , isrt[p] = ;
else ch[pre[p]][ch[pre[p]][] == p] = o;
pre[o] = pre[p];
ch[o][kind] = p, pre[p] = o;
pushup(p), pushup(o);
}
void splay(int o) {
push(o);
while (!isrt[o]) {
if (isrt[pre[o]]) rotate(o, ch[pre[o]][] == o);
else {
int p = pre[o], kind = ch[pre[p]][] == p;
if (ch[p][kind] == o) rotate(o, !kind), rotate(o, kind);
else rotate(p, kind), rotate(o, kind);
}
}
}
void access(int o) {
int y = ;
while (o) {
splay(o); size[o] -= size[ch[o][]];
isrt[ch[o][]] = , isrt[ch[o][] = y] = ;
o = pre[y = o];
pushup(o);
}
}
void makeroot(int o) {
access(o), splay(o);
rev[o] ^= , swap(ch[o][], ch[o][]);
}
void link(int x, int y) {
if (!x || !y) return;
makeroot(x); pre[x] = y;
}
void cut(int x, int y) {
if (!x || !y) return;
makeroot(x), access(y), splay(y);
size[y] -= size[x];
ch[y][] = pre[x] = , isrt[x] = ;
}
int query(int x, int y) {
makeroot(x), access(y), splay(y);
return size[ch[y][]]+;
}
int insert(int x) {
if (!root) {
root = x; S.insert(x); return ;
}
int pre = *(--S.lower_bound(x)), nex = *(S.upper_bound(x)), o;
if (pre == -INF) o = nex;
else if (nex == INF) o = pre;
else {
int depx = query(root, pre), depy = query(root, nex);
if (depx > depy) o = pre;
else o = nex;
}
f[x] = o, c[o][x > o] = x; link(o, x); S.insert(x);
return query(root, x);
}
int find_min() {
int o = *(++S.begin()), fa = f[o], child = c[o][];
int ans = query(root, o);
if (o != root) {
cut(o, fa), cut(child, o), link(child, fa), link(root, o);
c[o][] = root, f[root] = o; root = o; f[o] = ; c[fa][] = child, f[child] = fa;
}
return ans;
}
int find_max() {
int o = *(--(--S.end())), fa = f[o], child = c[o][];
int ans = query(root, o);
if (o != root) {
cut(o, fa), cut(child, o), link(child, fa), link(root, o);
c[o][] = root, f[root] = o; root = o; f[o] = ; c[fa][] = child, f[child] = fa;
}
return ans;
}
int del_min() {
int o = *(++S.begin()), fa = f[o], child = c[o][];
int ans = query(root, o);
cut(o, fa), cut(o, child); link(fa, child);
f[child] = fa, c[fa][] = child;
S.erase(S.find(o)); f[o] = c[o][] = c[o][] = ;
if (root == o) root = child, f[child] = ;
return ans;
}
int del_max() {
int o = *(--(--S.end())), fa = f[o], child = c[o][];
int ans = query(root, o);
cut(o, fa), cut(o, child); link(fa, child);
f[child] = fa, c[fa][] = child;
S.erase(S.find(o)); f[o] = c[o][] = c[o][] = ;
if (root == o) root = child, f[child] = ;
return ans;
}
}T; void work() {
scanf("%d", &m);
for (int i = ; i <= m; i++) {
scanf("%d", &q[i].opt);
if (q[i].opt == ) {
scanf("%d", &q[i].x); a[++top] = q[i].x;
}
}
sort(a+, a++top); top = unique(a+, a+top+)-a-;
for (int i = ; i <= m; i++) {
if (q[i].opt == ) printf("%d\n", T.insert(lower_bound(a+, a+top+, q[i].x)-a));
else if (q[i].opt == ) printf("%d\n", T.find_min());
else if (q[i].opt == ) printf("%d\n", T.find_max());
else if (q[i].opt == ) printf("%d\n", T.del_min());
else printf("%d\n", T.del_max());
}
}
int main() {
work();
return ;
}
[HNOI 2017]单旋的更多相关文章
- bzoj4825 [Hnoi2017]单旋
Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...
- BZOJ:4825: [Hnoi2017]单旋
Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...
- bzoj 4825: [Hnoi2017]单旋 [lct]
4825: [Hnoi2017]单旋 题意:有趣的spaly hnoi2017刚出来我就去做,当时这题作死用了ett,调了5节课没做出来然后发现好像直接用lct就行了然后弃掉了... md用lct不知 ...
- 【BZOJ4825】【HNOI2017】单旋(Link-Cut Tree)
[BZOJ4825][HNOI2017]单旋(Link-Cut Tree) 题面 题面太长,懒得粘过来 题解 既然题目让你写Spaly 那就肯定不是正解 这道题目,让你求的是最大/最小值的深度 如果有 ...
- HNOI2017 单旋
题目描述 网址:https://www.luogu.org/problemnew/show/3721 大意: 有一颗单旋Splay(Spaly),以key值为优先度,总共有5个操作. [1] 插入一个 ...
- 「AHOI / HNOI2017」单旋
「AHOI / HNOI2017」单旋 题目链接 H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种 ...
- HNOI2017单旋
单旋 这道题做法贼多,LCT,splay,线段树什么的貌似都行. 像我这种渣渣只会线段树了(高级数据结构学了也不会用). 首先离线所有操作,因为不会有两个点值重复,所以直接离散. 一颗线段树来维护所有 ...
- P3721 [AH2017/HNOI2017]单旋
题目:https://www.luogu.org/problemnew/show/P3721 手玩一下即可AC此题. 结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它 ...
- 洛谷P3721 单旋
什么毒瘤...... 题意:模拟一棵单旋splay,求每次插入,splay最值,删除最值的操作次数. 解:乍一看感觉很神,又因为是LCT题单上的,然后就折磨了我好久,最后跑去看题解... 居然是手玩找 ...
随机推荐
- springboot集成mybatisplus
介绍: Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发.提高效率而生.(摘自mybatis-plus官网)Mybati ...
- python web——Django架构
环境:windows/linux/OS 需要的软件:Firefox 浏览器(别的也可以 不过firfox和python的webdriver兼容性好) git版本控制系统(使用前要配置 用户 编辑器可以 ...
- alpha-咸鱼冲刺day2-紫仪
总汇链接 一,合照 emmmmm.自然是没有的. 二,项目燃尽图 三,项目进展 今天并没有什么进展,弄了好久好像也只研究出怎么把JS的功能块插入进去.html的信息提交这些还不知道要怎么弄. 四,问题 ...
- 20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计
20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 ...
- B-day7
1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:美化了登录页面,对导入导出的bug进行相关修改,对用户编辑页面进行相关美化,对第三方逻辑进行相应调整. 今天解决的进度:解决了导入和导出 ...
- win7开启wifi
在启用本地共享连接时,出现的错误! 我已经建了一个无线临时网络,来启用共享用来上网的!Internet连接共享访问被启用时,出现了一个错误(null)?而且这错误也会在系统日志里留下记录,都是些莫名其 ...
- collections deque队列及其他队列
from collections import deque dq = deque(range(10),maxlen=10) dq.rotate(3)#队列旋转操作接受一个参数N,让N>0时,队列 ...
- SELinux与进程管理
- linux 下 nc 命令的使用
netcat被誉为网络安全界的'瑞士军刀',一个简单而有用的工具,透过使用TCP或UDP协议的网络连接去读写数据.它被设计成一个稳定的后门工具,能够直接由其它程序和脚本轻松驱动.同时,它也是一个功能强 ...
- python的命名空间
Python的命名空间是Python程序猿必须了解的内容,对Python命名空间的学习,将使我们在本质上掌握一些Python中的琐碎的规则. 接下来我将分四部分揭示Python命名空间的本质:一.命名 ...