由于数据结构上老师讲了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. 解压版Tomcat配置

    解压版Tomcat配置(本例Tomcat6):   一 配置Tomcat 1 下载Tomcat Zip压缩包,解压.      如果增加tomcat的用户名和密码,则修改/conf/tomcat-us ...

  2. javascript 中正则表达式应用

    <script type="text/javascript"> var str="<script type='text/javascript'> ...

  3. Laravel学习笔记(五)数据库 数据库迁移案例2——创建数据结构,数据表,修改数据结构

    默认假设 所有的列在定义的时候都有默认的假设,你可以根据需要重写. Laravel假定每个表都有一个数值型的主键(通常命名为”id”),确保新加入的每一行都是唯一的.Laravel只有在每个表都有数值 ...

  4. Erlang初学

    这篇文章主要介绍了Erlang初学:Erlang的一些特点和个人理解总结,本文总结了函数式编程.一切都是常量.轻量进程.进程端口映射及典型缺点等内容,需要的朋友可以参考下 我对 Erlang 编程理念 ...

  5. 尚学堂Spring视频教程(一):模拟Spring

    Spring简单的说就是作为控制反转的容器,看这篇文章前需要先搞懂“控制反转和依赖注入“这个设计模式 我们先来模拟Spring,实现用户添加的功能,新建WEB项目”Spring_0100_Abstra ...

  6. printf()输出

    printf()函数是式样化输出函数, 一般用于向准则输出设备按规定式样输出消息.正在编写步骤时经常会用到此函数.printf()函数的挪用式样为: printf("<式样化字符串&g ...

  7. 开发android App干坏事(一)

    最近都是在搞java,android的知识,前两天生日朋友和我聊到,有一个认识的人通过反编译android程序往里面插入广告积分墙赚了很大一笔钱,很短时间内赚了几十万,(为毛感觉这已经是扯淡篇了,转入 ...

  8. Row_Number()显示行号

    SELECT *, Row_Number() OVER (partition by deptid ORDER BY salary desc) rank FROM employee Row_Number ...

  9. LoadRunner测试结果分析03 转载至zhangzhe的新浪博客

    LoadRunner测试结果分析之我见 前面分析的Web Resource(网络资源)的测试情况,其主要关注的是服务器性能,而系统本身和环境都有可能存在问题,页面诊断(Web Page Diagnos ...

  10. click 事件 arguments.callee 每次点击自动* 2

    今天在测试JQUERY(版本3.0,向下兼容3.0)时发现一个很特别的现象,代码如下: $($('button').get(4)).click(function(){ alert($(this).ht ...