由于数据结构上老师讲了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初探的更多相关文章

  1. nyist 606 ACM之路

    http://acm.nyist.net/JudgeOnline/problem.php?pid=606 ACM之路 时间限制:1000 ms | 内存限制:65535 KB 描述 转眼间,12级新生 ...

  2. ACM之路(19)—— 主席树初探

    长春赛的 I 题是主席树,现在稍微的学了一点主席树,也就算入了个门吧= = 简单的来说主席树就是每个节点上面都是一棵线段树,但是这么多线段树会MLE吧?其实我们解决的办法就是有重复的节点给他利用起来, ...

  3. ACM之路

    从10月我刚接触到acm竞赛,到现在2017年2.20接近4个月的时间,我才刷到200道题.在刷题的过程中,我曾遇到困难,我也从一次性就a过,但是有时候会想到放弃.不过既然已经踏进来一只脚,还不如就好 ...

  4. 另一个ACM之路建议

    ACM联系建议 一位高手对我的建议: 一般要做到50行以内的程序不用调试.100行以内的二分钟内调试成功.acm主要是考算法的 ,主要时间是花在思考算法上,不是花在写程序与debug上. 下面给个计划 ...

  5. ACM之路——上车了

    校赛坚持到底,拿到了银牌:第一批进入ACM队集训,期末考试之前仍然代码不断,甚至感觉对不起大学第一次的期末考试,五天复习高数,两天复习英语,看到英语成绩是胸口突然好痛,好难受……就为了成为ACM正式队 ...

  6. 剪辑的楼天城的ACM之路

    楼天城楼教主的acm心路历程(剪辑) 利用假期空闲之时,将这几年GCJ,ACM,TopCoder 参加的一些重要比赛作个回顾.昨天是GCJ2006 的回忆,今天时间上更早一些吧,我现在还清晰记得3 年 ...

  7. ACM之路(转载)

    转载自:https://www.cnblogs.com/tianjintou/p/4139416.html 要注意,ACM的竞赛性强,因此自己应该和自己的实际应用联系起来. 适合自己的才是好的,有的人 ...

  8. Android开发学习之路-RecyclerView使用初探

    在进行一些MaterialDesign规范开发的时候,比如之前说到的CoordinateLayout实现的向上折叠效果的时候,如果依然使用ListView,那么这种效果是做不出来的,因为ListVie ...

  9. NOIP2012 借教室 Splay初探

    终于把区间操作的Splay搞明白了…… Splay的大致框架是这样的: [代码中的Zig-Zig和Zig-Zag操作其实是可以优化的,实际只需要3次passDown和3次update] templat ...

随机推荐

  1. Unity关于一个UGUI优化效率的方法

    无意间发现了一个小技巧.如下图所示,可以发现UGUI的Image组件的RaycastTarget勾选以后会消耗一些效率,为了节省效率就不要勾选它了,不仅Image组件Text组件也有这样的问题. 一般 ...

  2. IOC框架整体介绍

    1.Castle Windsor 2.Autofac 3.Unity 4.Spring.NET 5.StructureMap 6.Ninject

  3. spring mvc 4 校验

    一.controller中添加: @ResourceGatewayValidator gatewayValidator; @RequestMapping(value = "/gateway/ ...

  4. jquery文本框内容改变事件

    /** * 内容改变时并不会触发事件,但是在失去焦点的时候会触发. */ $("#inputid").change(function(){ console.log($(this). ...

  5. css3画三角形的原理

    以前用过css3画过下拉菜单里文字后面的“下拉三角符号”,类似于下面这张图片文字后面三角符号的效果 下面是一个很简单的向上的三角形代码 #triangle-up { width: 0; height: ...

  6. CentOS 6.5下静默安装oracle

    本例: 通过SSH远程连接云主机,上传oracle11g安装包,在centos6.5上无图形化界面静默安装oracle11g. 涉及工具及环境: 1.本地环境windows7+ssh远程连接工具xSh ...

  7. Mono 异步加载数据更新主线程

    主要是用 async和 await 调用 RunOnUiThread来更新. 调用函数: //异步加载数据开始 doInBackground (); //异步加载数据开始end protected a ...

  8. jQuery中关于height,innerWidth与outerWidth的区别

    jQuery width() 和 height() 方法 width() 方法设置或返回元素的宽度(不包括内边距.边框或外边距). height() 方法设置或返回元素的高度(不包括内边距.边框或外边 ...

  9. install cx_Oracle on Linux

    step 1 : install oracle client library url: http://www.oracle.com/technetwork/topics/linuxsoft-08280 ...

  10. 杭电acm 1003

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> usin ...