【LG3721】[HNOI2017]单旋
【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]单旋的更多相关文章
- bzoj 4825: [Hnoi2017]单旋 [lct]
4825: [Hnoi2017]单旋 题意:有趣的spaly hnoi2017刚出来我就去做,当时这题作死用了ett,调了5节课没做出来然后发现好像直接用lct就行了然后弃掉了... md用lct不知 ...
- 4825: [Hnoi2017]单旋
4825: [Hnoi2017]单旋 链接 分析: 以后采取更保险的方式写代码!!!81行本来以为不特判也可以,然后就总是比答案大1,甚至出现负数,调啊调啊调啊调~~~ 只会旋转最大值和最小值,以最小 ...
- [BZOJ4825][HNOI2017]单旋(线段树+Splay)
4825: [Hnoi2017]单旋 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 667 Solved: 342[Submit][Status][ ...
- 【BZOJ4825】[Hnoi2017]单旋 线段树+set
[BZOJ4825][Hnoi2017]单旋 Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能 ...
- bzoj4825 [Hnoi2017]单旋
Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...
- BZOJ:4825: [Hnoi2017]单旋
Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...
- HNOI2017 单旋
题目描述 网址:https://www.luogu.org/problemnew/show/3721 大意: 有一颗单旋Splay(Spaly),以key值为优先度,总共有5个操作. [1] 插入一个 ...
- HNOI2017单旋
单旋 这道题做法贼多,LCT,splay,线段树什么的貌似都行. 像我这种渣渣只会线段树了(高级数据结构学了也不会用). 首先离线所有操作,因为不会有两个点值重复,所以直接离散. 一颗线段树来维护所有 ...
- P3721 [AH2017/HNOI2017]单旋
题目:https://www.luogu.org/problemnew/show/P3721 手玩一下即可AC此题. 结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它 ...
随机推荐
- C#实现字符串计算
借用DataTable的Compute函数进行计算. string formula = "1+1*4/3+23*(1+2)"; DataTable dt = new DataTab ...
- 执行SQL的DbHelperSQL
using System; using System.Collections; using System.Collections.Specialized; using System.Data; usi ...
- 关于easyUI
<input class="easyui-combobox" id="s_dataDicName" data-options="panelHei ...
- datediff
DateDiff()是计算机函数. 中文名 日期比较函数 外文名 DateDiff() 作 用 得 出两个日期之间的间隔 用 途 返回两个日期之间的差值 允许数据类型 timeinterv ...
- 转:HTTP Status 404(The requested resource is not available)的几种解决方法
原文地址 原因:servlet没有配置正确 ,查看web.xml确认正确,以及自己的请求路径正确 在IE中提示“404”错误有以下三种情况 1.未部署Web应用 2.URL输入错误 排错方法: 首先, ...
- python操作Exchange邮箱实例(-)
需求很简单,就是实现按公司域名及服务器模拟exchange发送邮件,主要是协助自动化测试.主要功能:收件人/抄送/正文html/附件 本实例基于:python2.7.11 exchangelib1.1 ...
- Git修改子模块的路径
Git在两个地方存储有关子模块的信息.第一个是在一个名为的文件中.gitmodules,该文件被签入git存储库.对此文件的更改将传播到其他存储库. 另一个位置在.git/config,并且它是执行大 ...
- 安装OpenCV:OpenCV 3.0、OpenCV 2.4.8、OpenCV 2.4.9 +VS 开发环境配置(转)
安装根据这个配置的,但是opencv3.0安装不成功,后来改安2.48就可以了. http://blog.csdn.net/poem_qianmo/article/details/19809337/ ...
- IKVM.NET入门(1)
IKVM.NET是一个针对Mono和微软.net框架的java实现,其设计目的是在.NET平台上运行java程序.本文将比较详细的介绍这个工具的原理.使用入门(如何java应用转换为.NET应用.如何 ...
- ubuntu 12.04 64位 安装wps
1.去wps官网下载linux版的软件 http://community.wps.cn/download/ 我这里下载的是Alpha版的kingsoft-office_9.1.0.4280~a12p4 ...