【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. 关于Matlab里面的四个取整(舍入)函数:Floor, Ceil, Fix, Round的解释(转)

    转自http://blog.sina.com.cn/s/blog_48ebd4fb010009c2.html   floor:朝负无穷方向舍入 B = floor(A) rounds the elem ...

  2. [EffectiveC++]item26:尽可能延后变量定义式的出现时间

  3. 循环while 和 continue

    while 1: print("行动吧") # 组成:while 条件: #条件为真,则执行语句块.之后再回去判断条件是否为真,再执行....till条件为假为止. 语句块 # 条 ...

  4. 教你用 jVectorMap 制作属于自己的旅行足迹

    jVectorMap JVectorMap 是一个优秀的.兼容性强的 jQuery 地图插件. 它可以工作在包括 IE6 在内的各款浏览器中,矢量图输出,除官方提供各国地图数据外,用户可以使用数据转换 ...

  5. tkinter入门,canvas实现百度,抖音,加载

    对于tkinter的各个控件,可以参看  : https://blog.csdn.net/weixin_38532159/article/details/78379523 这个已经比较全面了 今天利用 ...

  6. 【转】.net core 一次坑爹的类库打包过程

    自己遇到这个问题,记录一下,原文链接:http://www.cnblogs.com/Hai--D/p/5776463.html. 众所周知,.net core 跨平台类库引用一定要通过nuget获得. ...

  7. reactor模型框架图和流程图 libevent

    学习libevent有助于提升程序设计功力,除了网络程序设计方面外,libevent的代码里有很多有用的设计技巧和基础数据结构,比如信息隐藏.函数指针.c语言的多态支持.链表和堆等等,都有助于提升自身 ...

  8. Golang reflect 反射

    反射的规则如下: 从接口值到反射对象的反射  从反射对象到接口值的反射  为了修改反射对象,其值必须可设置   -------------------------------------------- ...

  9. BigDecimalUtil 工具类

    一.为什么要用BigDecimal? 涉及到加减乘除,用int,double 会出现数据丢失,这个时候就要用BigDecimal. 注意:在new BigDecimal(Double.toString ...

  10. 一般处理程序中用到session时

    一般处理程序ashx文件使用session 1.先引用System.Web.SessionState这个命名空间, 2.如果是要在HttpHandler中读取Session的内容,就要在实现IHttp ...