[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题单上的,然后就折磨了我好久,最后跑去看题解... 居然是手玩找 ...
随机推荐
- 使用Java客户端操作elasticsearch
Java REST客户端有两种风格: Java低级别REST客户端(Java Low Level REST Client,以后都简称低级客户端算了,难得码字):Elasticsearch的官方low- ...
- eoLinker API-Shop 抓住区块链机遇,从这些API开始
区块链是分布式存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.所谓共识机制是区块链系统中实现不同节点之间建立信任.获取权益的数学算法. 区块链目前分为三类: 公有区块链(PublicB ...
- C语言博客作业--函数
一.PTA实验作业 题目1 (6-7) (1).本题PTA提交列表 (2)设计思路 设计第一个函数判断是否完数int factorsum( int number ) 定义sum.i:sum初始化归0, ...
- C++之异常捕获和处理
一.简介 在C++语言中,异常处理包括:throw表达式,try语句块,一套异常类.其中,异常类用于在throw表达式和相关的catch子句之间传递异常的具体信息.exception头文件定义了最 ...
- 项目Alpha冲刺Day8
一.会议照片 二.项目进展 1.今日安排 前端界面框架基本完成,剩下侧边栏与权限相关部分未完成.前端路由异常拦截完成.项目结构与开发流程规定完成.后台开发规定小变更. 2.问题困难 组件的拆分与否和组 ...
- http post/get 2种使用方式
public class HttpUtil { //HttpPost public static String executePost(String url, List<NameValue ...
- TOTP算法 基于时间的一次性密码
/** Copyright (c) 2011 IETF Trust and the persons identified as authors of the code. All rights rese ...
- Scala 快速入门
 Scalable 编程语言 纯正的的面向对象语言 函数式编程语言 无缝的java互操作 scala之父 Martin Odersky 1. 函数式编程 函数式编程(functional progr ...
- LeetCode & Q217-Contains Duplicate-Easy
Array Hash Table Description: Given an array of integers, find if the array contains any duplicates. ...
- Python-字符串及列表操作-Day2
1.数据类型 1.1 变量引出数据类型 变量:用来记录状态变量值的变化就是状态的变化,程序运行的本质就是来处理一系列的变化 1.2 五大基本数据类型: 数字 字符串 列表 元组 字典 1.2.1 数字 ...