【LG3721】[HNOI2017]单旋

题面

洛谷

题解

20pts

直接模拟\(spaly\)的过程即可。

100pts

可以发现单旋最大、最小值到根,手玩是有显然规律的,发现只需要几次\(link,cut\),那么我们维护原树的父子关系以及一颗\(LCT\)。

对于插入操作,由于插入的值肯定在前驱的右儿子或后继的左儿子,用\(set\)维护前驱后继即可。

建议自己独立找出规律,这里不再赘述,这题其实细节还是挺多的。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int MAX_N = 2e5 + 5;
struct Node { int ch[2], fa, size; bool rev; } t[MAX_N];
struct Clone { int v, ls, rs, fa; } _t[MAX_N];
int root, tot;
bool get(int x) { return t[t[x].fa].ch[1] == x; }
bool nroot(int x) { return t[t[x].fa].ch[0] == x || t[t[x].fa].ch[1] == x; }
void pushup(int x) { t[x].size = t[t[x].ch[0]].size + t[t[x].ch[1]].size + 1; }
void putrev(int x) { swap(t[x].ch[0], t[x].ch[1]); t[x].rev ^= 1; }
void pushdown(int x) {
if (!t[x].rev) return ;
if (t[x].ch[0]) putrev(t[x].ch[0]);
if (t[x].ch[1]) putrev(t[x].ch[1]);
t[x].rev = 0;
}
void rotate(int x) {
int y = t[x].fa, z = t[y].fa, k = get(x);
if (nroot(y)) t[z].ch[get(y)] = x;
t[x].fa = z;
t[t[x].ch[k ^ 1]].fa = y, t[y].ch[k] = t[x].ch[k ^ 1];
t[y].fa = x, t[x].ch[k ^ 1] = y;
pushup(y), pushup(x);
}
void splay(int x) {
static int stk[MAX_N], top;
stk[top = 1] = x;
for (int i = x; nroot(i); i = t[i].fa) stk[++top] = t[i].fa;
for (int i = top; i; --i) pushdown(stk[i]);
while (nroot(x)) {
int y = t[x].fa;
if (nroot(y)) get(x) ^ get(y) ? rotate(x) : rotate(y);
rotate(x);
}
}
void access(int x) { for (int y = 0; x; y = x, x = t[x].fa) splay(x), t[x].ch[1] = y, pushup(x); }
void makeroot(int x) { access(x); splay(x); putrev(x); }
void link(int x, int y) { makeroot(x); t[x].fa = y; }
void split(int x, int y) { makeroot(x); access(y); splay(y); }
void cut(int x, int y) { split(x, y); t[x].fa = t[y].ch[0] = 0; pushup(y); }
set<int> st;
map<int, int> mp;
void insert(int v) {
int x = ++tot;
mp[v] = x, _t[x].v = v;
if (st.size() == 0) return st.insert(v), root = x, (void)puts("1");
set<int> :: iterator ite = st.upper_bound(v);
if (ite == st.end() || _t[mp[*ite]].ls) {
--ite;
int tmp = mp[*ite];
link(x, tmp), _t[tmp].rs = x, _t[x].fa = tmp;
} else {
int tmp = mp[*ite];
link(x, tmp), _t[tmp].ls = x, _t[x].fa = tmp;
}
st.insert(v);
return split(x, root), (void)printf("%d\n", t[root].size);
}
void splay_min() {
int x = mp[*st.begin()];
if (x == root) return (void)puts("1");
split(x, root); printf("%d\n", t[root].size);
cut(x, _t[x].fa); if (_t[x].rs) cut(x, _t[x].rs);
link(x, root); if (_t[x].rs) link(_t[x].fa, _t[x].rs);
_t[_t[x].fa].ls = _t[x].rs; if (_t[x].rs) _t[_t[x].rs].fa = _t[x].fa;
_t[x].fa = 0, _t[root].fa = x, _t[x].rs = root;
root = x;
}
void splay_max() {
int x = mp[*st.rbegin()];
if (x == root) return (void)puts("1");
split(x, root); printf("%d\n", t[root].size);
cut(x, _t[x].fa); if (_t[x].ls) cut(x, _t[x].ls);
link(x, root); if (_t[x].ls) link(_t[x].ls, _t[x].fa);
_t[_t[x].fa].rs = _t[x].ls; if (_t[x].ls) _t[_t[x].ls].fa = _t[x].fa;
_t[x].fa = 0, _t[root].fa = x, _t[x].ls = root;
root = x;
}
void del_min() {
int x = mp[*st.begin()];
if (root == x) {
puts("1");
if (_t[x].rs) cut(x, _t[x].rs);
_t[_t[x].rs].fa = 0, root = _t[x].rs;
st.erase(st.begin());
return ;
}
split(x, root); printf("%d\n", t[root].size);
cut(x, _t[x].fa); if (_t[x].rs) cut(x, _t[x].rs);
if (_t[x].rs) link(_t[x].fa, _t[x].rs);
_t[_t[x].fa].ls = _t[x].rs; if (_t[x].rs) _t[_t[x].rs].fa = _t[x].fa;
st.erase(st.begin());
}
void del_max() {
int x = mp[*st.rbegin()];
if (root == x) {
puts("1");
if (_t[x].ls) cut(x, _t[x].ls);
_t[_t[x].ls].fa = 0, root = _t[x].ls;
st.erase(--st.end());
return;
}
split(x, root); printf("%d\n", t[root].size);
cut(x, _t[x].fa); if (_t[x].ls) cut(x, _t[x].ls);
if (_t[x].ls) link(_t[x].ls, _t[x].fa);
_t[_t[x].fa].rs = _t[x].ls; if(_t[x].ls) _t[_t[x].ls].fa = _t[x].fa;
st.erase(--st.end());
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
int M = gi();
for (int i = 1; i <= M; i++) {
int op = gi();
switch (op) {
case 1: insert(gi()); break;
case 2: splay_min(); break;
case 3: splay_max(); break;
case 4: del_min(); break;
case 5: del_max(); break;
}
}
return 0;
}

【LG3721】[HNOI2017]单旋的更多相关文章

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

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

  2. 4825: [Hnoi2017]单旋

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

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

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

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

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

  5. bzoj4825 [Hnoi2017]单旋

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

  6. BZOJ:4825: [Hnoi2017]单旋

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

  7. HNOI2017 单旋

    题目描述 网址:https://www.luogu.org/problemnew/show/3721 大意: 有一颗单旋Splay(Spaly),以key值为优先度,总共有5个操作. [1] 插入一个 ...

  8. HNOI2017单旋

    单旋 这道题做法贼多,LCT,splay,线段树什么的貌似都行. 像我这种渣渣只会线段树了(高级数据结构学了也不会用). 首先离线所有操作,因为不会有两个点值重复,所以直接离散. 一颗线段树来维护所有 ...

  9. P3721 [AH2017/HNOI2017]单旋

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

随机推荐

  1. Replace-iOS

    Replace-iOS https://github.com/MartinRGB/Replace-iOS 看了下demo,运行起来超卡...... Simply Implement Zee Young ...

  2. Linux bzip2命令详解

    Linux bzip/bunzip2命令是.bz2文件的解压缩程序. bunzip2可解压缩.bz2格式的压缩文件.bunzip2实际上是bzip2的符号连接,执行bunzip2与bzip2 -d的效 ...

  3. Git使用本地仓库之基本操作

    1.Git是什么? 一个分布式版本控制系统,和SVN类似,但远比SVN强大的一个版本控制系统 ①Git可以方便的在本地进行版本管理,如同你本地有一个版本管理服务器一样我们可以选择在合适的时间将本地版本 ...

  4. 【数据结构】 顺序表查找(折半查找&&差值查找)

    #include <stdio.h> #include <stdlib.h> #include <time.h> #define MAXSIZE 10 首先构造一个 ...

  5. java判断字符串内容

    java判断字符串是否全为数字 String str = "032";boolean isNum = str.matches("[0-9]+"); java判断 ...

  6. September 09th 2017 Week 36th Saturday

    Don't wait to be lonely, to recognize the value of a friend. 不要等到孤独了,才明白朋友的价值. Don't wait to be left ...

  7. APUE 12.7 取消选项

  8. 利用Gson将JSON数据进行格式化(pretty print)

    我们可以利用Gson包将String类型的JSON数据进行格式化. Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonPa ...

  9. python第十五课——全局变量and局部变量

    全局变量&局部变量: 全局变量的特点: 1).直接定义在.py文件中(函数外)的变量(全局位置) 2).作用域比较大,可以被此文件中的任何函数所使用 局部变量的特点:1).定义在函数内部(函数 ...

  10. 学习python第三天数据库day2

    day01回顾: 数据库: 定义:存储数据的仓库(database,简称db) 常用的数据库对象有哪些? 1).数据表(table) ***** 2).视图(view) 3).索引(index) 4) ...