【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. RHEL7系统管理之网络管理

    1. RHEL7的网络介绍 在RHEL7中, NetworkManager 提供的默认联网服务是一个动态网络控制和配置守护进程, 支持ifcfg类型的配置文件. NetworkManager 可用于连 ...

  2. JBoss jmx-console中的秘密

    JBoss jmx-console中的秘密 https://wenku.baidu.com/view/fe196f047cd184254b35351d.html

  3. Dos命令删除添加新服务

    安装服务sc create Svnservice binpath= "d:\subversion\bin\svnserve.exe --service -r E:\projectversio ...

  4. [控件] ChangeColorLabel

    ChangeColorLabel 效果 源码 // // ChangeColorLabel.h // YXMWeather // // Created by XianMingYou on 15/6/2 ...

  5. Linux 新建用户和组命令

    用户的角色是通过UID和GID识别的. UID用户ID:相当于各为的身份证,在系统中是唯一的 GID组ID:相当于各为的家庭或者你们的学校. 1.新建用户及设置密码命令如下: useradd [参数] ...

  6. Linux 系统调整内核参数

    调整系统内核参数 内核优化:Linux系统(内核 + shell + 应用程序)       针对业务服务应用而进行的系统内核参数调整(主要是/etc/sysctl.conf文件) 1. vim /e ...

  7. marquee 标签的鼠标放上去滚动效果 鼠标离开继续滚动

    效果很实用,可以轻松的实现鼠标放上去停止滚动.鼠标离开继续滚动的效果.下面是具体的用法(特别注意onMouseOver和onMouseOut是需要同时写进去才会出现比较好的效果):onMouseOut ...

  8. tomcat7换端口号调试

    1.C:\tomcat\conf\server.xml中修改端口号 2.C:\tomcat\bin\startup.bat批处理文件启动tomcat 3.用ctrl+c结束批处理文件 4.调试结束

  9. 使用js插件进行设备检测

    一.分析新浪网是怎么做的   如新浪网有两种版本,一种是pc版,存放在www.sina.com.cn这个服务器上:另外一种是手机版,存放在www.sina.cn这个服务器上 原理是当用户输入网址www ...

  10. springboot 配置jpa启动报Error processing condition on org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration.pageableCustomizer

    springboot +gradle 配置jpa启动报Error processing condition on org.springframework.boot.autoconfigure.data ...