ACM之路(20)—— Splay初探
由于数据结构上老师讲了AVL树的rotate,然后去学了一下treap和Splay,这些数据结构还真是神奇啊!
treap暂时只知道名次树的作用(就是一段动态变化的有序数列,找第K大的元素,用set显然是O(n)的。。)。
好,正式介绍SplayTree这个神奇的数据结构:暂时的理解是,用于解决一些线段树解决不了的区间问题,比方说区间翻转,区间删除并插入等等(似乎分块也可以解决一些xjbg的区间问题)。。然后,Splay还可以解决掉LCT的问题(暂时还不会,,下次继续学习)。
然后就愉快地掏出模板吧(直接修改了铭神的模板)。。仓鼠挂的平衡树。
G题,区间翻转+区间切割的。直接掏出模板套上去就是了:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define tochange (root->ch[1]->ch[0])
using namespace std;
const int N = + ;
struct node *nill, *root;
struct node {
int val;
int sz;
bool rev;
node *ch[],*fa;
void init(int v = )
{
ch[] = ch[] = fa = nill;
val = v;
sz = ;
}
void up() {
if (this==nill) return ;
sz = ch[]->sz + ch[]->sz + ;
}
void down() {
if (this==nill) return ;
if(rev)
{
rev = false;
ch[]->rev ^= ;
ch[]->rev ^= ;
swap(ch[], ch[]);
}
}
bool d() {
return fa->ch[]==this;
}
void reverse() {
rev ^= ;
std::swap(ch[],ch[]);
}
void setc(node *o,int c) {
ch[c] = o;
o->fa = this;
up();
}
void rot() {
int c = d(),cc = fa->d();
node *z = fa->fa;
node *tmp = fa;
fa->setc(ch[c^],c);
setc(tmp,c^);
if(z!=nill) z->setc(this,cc);
else fa = z; // 这里的if-else不加也行,因为对于nill来说无论儿子是谁都无所谓,
// 并且,setc时的up对nill无效
}
void D() {
if (this==nill) return ;
fa->D();
down();
}
void splay(node *aim = nill) {
D();
while (fa!=aim) {
if (fa->fa!=aim) {
d()==fa->d() ? fa->rot() : rot();
}
rot();
}
if(aim == nill) root = this;
}
}memo[N], *bat; node* findK(node* o, int k)
{
while()
{
o->down();
if(o->ch[]->sz + == k)
{
return o;
}
if(o->ch[]->sz >= k) o = o->ch[];
else
{
k -= o->ch[]->sz + ;
o = o->ch[];
}
}
} node* get_min(node* o)
{
/*while(o->ch[0] != nill)
{
o->down();
o = o->ch[0];
}
return o;*/
// 上面写法错了,为什么?
// -因为可能o本来是没有左边的儿子的,一交换以后就有了,所以要先down().
o->down();
while(o->ch[] != nill)
{
o = o->ch[];
o->down();
}
return o;
} void Reverse(int a,int b)
{
node* x = findK(root,a);
node* y = findK(root,b+);
x->splay();
y->splay(root);
tochange->rev ^= ;
} void Cut(int a,int b,int c)
{
node* x = findK(root, a);
node* y = findK(root, b+);
x->splay();
y->splay(root);
node* temp = tochange;
y->setc(nill, );
node* z = findK(root, c+);
z->splay();
z = get_min(root->ch[]);
z->splay(root);
root->ch[]->setc(temp, );
} int n,m;
node* newNode(int val = )
{
node* o = bat ++;
o->init(val);
return o;
}
void init()
{
bat = memo;
nill = newNode(); nill->sz = ;
root = newNode(); root->fa = nill;
node* p = newNode(), *p2 = nill;
root->setc(p, );
p = nill;
for(int i=;i<=n;i++)
{
p2 = newNode(i);
p2->setc(p, );
p = p2;
}
root->ch[]->setc(p, );
} int cnt = ;
void print(node* o)
{
if(o == nill) return ;
o->down();
print(o->ch[]);
if(cnt >= && cnt <= n)
{
if(cnt > ) printf(" ");
printf("%d",o->val);
}
cnt++;
print(o->ch[]);
} int main()
{
while(scanf("%d%d",&n,&m) == )
{
if(n == - && m == -) break;
init(); char s[];
while(m--)
{
scanf("%s",s);
if(s[] == 'F')
{
int a,b;scanf("%d%d",&a,&b);
Reverse(a,b);
}
else
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Cut(a,b,c);
}
}
cnt = ;
print(root);
puts("");
}
}
Splay区间翻转+区间切割
然后A题,可以直接map写,然后弹出最大最小就可以了。为了练手Splay,特地用Splay写了一遍(惊喜的是时间比map的要短= =)。
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define tochange (root->ch[1]->ch[0])
using namespace std;
const int N = + ;
struct node *nill, *root;
struct node {
int val, key;
int sz;
bool rev;
node *ch[],*fa;
void init(int v,int p)
{
ch[] = ch[] = fa = nill;
val = v;
key = p;
sz = ;
}
void up() {
if (this==nill) return ;
sz = ch[]->sz + ch[]->sz + ;
}
void down() {
if (this==nill) return ;
if(rev)
{
rev = false;
ch[]->rev ^= ;
ch[]->rev ^= ;
swap(ch[], ch[]);
}
}
bool d() {
return fa->ch[]==this;
}
void reverse() {
rev ^= ;
std::swap(ch[],ch[]);
}
void setc(node *o,int c) {
ch[c] = o;
o->fa = this;
up();
}
void rot() {
int c = d(),cc = fa->d();
node *z = fa->fa;
node *tmp = fa;
fa->setc(ch[c^],c);
setc(tmp,c^);
if(z!=nill) z->setc(this,cc);
else fa = z;
}
void D() {
if (this==nill) return ;
fa->D();
down();
}
void splay(node *aim = nill) {
D();
while (fa!=aim) {
if (fa->fa!=aim) {
d()==fa->d() ? fa->rot() : rot();
}
rot();
}
if(aim == nill) root = this;
}
}memo[N], *bat; node* newNode()
{
node* o = bat ++;
return o;
}
void init()
{
bat = memo;
nill = newNode(); nill->sz = ;
root = nill;
} void _insert(node* o, node* p)
{
if(p->key < o->key)
{
if(o->ch[] == nill) {o->setc(p, );return ;}
else _insert(o->ch[], p);
}
else if(p->key > o->key)
{
if(o->ch[] == nill) {o->setc(p, );return ;}
else _insert(o->ch[], p);
}
}
void insert(int val,int key)
{
node* p = newNode();
p->init(val, key);
if(root == nill) root = p;
else _insert(root, p);
} node* get_max_or_min(node* o, int op)
{
//o->down();
while(o->ch[op] != nill)
{
o = o->ch[op];
//o->down();
}
return o;
}
// 1->pop_max, 0->pop_min
void pop_max_or_min(int op)
{
if(root == nill) {printf("0\n");return;}
node* p = get_max_or_min(root, op);
p->splay(nill);
printf("%d\n",p->val);
root = p->ch[op^];
root->fa = nill;
} int main()
{
init();
int n;
while(scanf("%d",&n) == && n)
{
if(n == )
{
int val, key;scanf("%d%d",&val,&key);
insert(val,key);
}
else if(n == ) pop_max_or_min();
else pop_max_or_min();
}
return ;
}
Splay维护最大或最小key的节点
然后,,因为要复习了,暂时就放放了。。
ACM之路(20)—— Splay初探的更多相关文章
- nyist 606 ACM之路
http://acm.nyist.net/JudgeOnline/problem.php?pid=606 ACM之路 时间限制:1000 ms | 内存限制:65535 KB 描述 转眼间,12级新生 ...
- ACM之路(19)—— 主席树初探
长春赛的 I 题是主席树,现在稍微的学了一点主席树,也就算入了个门吧= = 简单的来说主席树就是每个节点上面都是一棵线段树,但是这么多线段树会MLE吧?其实我们解决的办法就是有重复的节点给他利用起来, ...
- ACM之路
从10月我刚接触到acm竞赛,到现在2017年2.20接近4个月的时间,我才刷到200道题.在刷题的过程中,我曾遇到困难,我也从一次性就a过,但是有时候会想到放弃.不过既然已经踏进来一只脚,还不如就好 ...
- 另一个ACM之路建议
ACM联系建议 一位高手对我的建议: 一般要做到50行以内的程序不用调试.100行以内的二分钟内调试成功.acm主要是考算法的 ,主要时间是花在思考算法上,不是花在写程序与debug上. 下面给个计划 ...
- ACM之路——上车了
校赛坚持到底,拿到了银牌:第一批进入ACM队集训,期末考试之前仍然代码不断,甚至感觉对不起大学第一次的期末考试,五天复习高数,两天复习英语,看到英语成绩是胸口突然好痛,好难受……就为了成为ACM正式队 ...
- 剪辑的楼天城的ACM之路
楼天城楼教主的acm心路历程(剪辑) 利用假期空闲之时,将这几年GCJ,ACM,TopCoder 参加的一些重要比赛作个回顾.昨天是GCJ2006 的回忆,今天时间上更早一些吧,我现在还清晰记得3 年 ...
- ACM之路(转载)
转载自:https://www.cnblogs.com/tianjintou/p/4139416.html 要注意,ACM的竞赛性强,因此自己应该和自己的实际应用联系起来. 适合自己的才是好的,有的人 ...
- Android开发学习之路-RecyclerView使用初探
在进行一些MaterialDesign规范开发的时候,比如之前说到的CoordinateLayout实现的向上折叠效果的时候,如果依然使用ListView,那么这种效果是做不出来的,因为ListVie ...
- NOIP2012 借教室 Splay初探
终于把区间操作的Splay搞明白了…… Splay的大致框架是这样的: [代码中的Zig-Zig和Zig-Zag操作其实是可以优化的,实际只需要3次passDown和3次update] templat ...
随机推荐
- GDB 调试遇到??的问题
今天总算解决了一个大的bug,爽! 我的程序crash,有了coredump文件,在Linux PC上用arm-linux-gdb debug it. The result is: #0 0x402 ...
- 我用VS2012在Nuget中安装Signalr之后报错
我用VS2012在Nuget中安装Signalr之后报错 “/”应用程序中的服务器错误. The following errors occurred while attempting to load ...
- Cookie实现商品浏览记录--方式一:Java实现
方式一:Java代码方式实现:此种方式实现思路较为顺畅.难点在于,如何实现将最近浏览的产品显示在最前面:实现方式是借助LinkedList提供的remove()方法,先将此id从列表中移除,然后再借助 ...
- ACdream 1017 [分层图][网络流]
/* 大连热身C题 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一个城市路线图,给定起点给定终点.有n个货物从起点运送到终点.城市的边是无向边. 每个货物每天如果通过某条路,那么这天这条路只能运 ...
- InfoPath中用户数据类型结构解析
由于缺少对“用户”数据类型结构的明确定义,在设计InfoPath表达式时往往会耗用大量时间尝试,而且不一定能得到期望结果.下面对用户数据类型的结构进行详细解析. >> 什么是用户数据类型 ...
- WinForms中的Label的AutoSize属性
当大量使用UserControl组合UI时,如果更改了Label的Text属性,Label.AutoSize属性会影响UserControl的OnLoad事件的发生顺序; public overrid ...
- UML6大关系
1.继承关系(inherit) 空心三角+实线 2.实现(接口)关系 空心三角+虚线 3.聚合关系(Aggregation,弱拥有,A对象可以包含B对象,但B对象不是A的一部分) 空心菱形+实线箭头 ...
- Jmeter组件6. SOAP/XML-RPC Request
Jmeter测试SOAP的web services现在有两种方式 第一是使用SOAP/XML-RPC Request组件,第二使用HTTP Request组件 Send SOAPACtion, 同ht ...
- Android 自定义表格显示数据
Android 自定义TextView控件,用来组成表格方便数据的展示. 首先看一下效果 样式不是很好看,需要用的可以自己优化一下. 实现方式很简单. 1.自定义控件 MyTableTextView ...
- 用rpm -e 将yum命令删除了,如何修复
系统环境: 物理机:Windows 10 家庭中文版 虚拟机:VMware Workstation 10 Linux发行版本:CentOS 6.5 相关信息查询: 首先查询,系统安装的yum包的信息: ...