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 ...
随机推荐
- 使用Spring+Junit4.4进行测试(使用注解)
http://nottiansyf.iteye.com/blog/345819 使用Junit4.4测试 在类上的配置Annotation @RunWith(SpringJUnit4ClassRunn ...
- App开放接口api安全性的设计与实现
前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证, 那么这就需要用户提供一些信息,比如用户名密码等 ...
- 大规模IP地址黑名单高性能查询实现
嗯……前阵子接了个活儿,需要做一个基于IP地址黑名单的分流网关.刚接到的时候心想iptables不就行了么,没想到一看客户给的IP黑名单规模……我擦……上亿个…… 黑名单到了这个规模,就不得不考虑下优 ...
- [转载]http协议 文件下载原理及多线程断点续传
最近研究了一下关于文件下载的相关内容,觉得还是写些东西记下来比较好.起初只是想研究研究,但后来发现写个可重用性比较高的模块还是很有必要的,我想这也是大多数开发人员的习惯吧.对于HTTP协议,向服务器请 ...
- RSA加密算法总结
RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准. RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进 ...
- ldap实现用户认证
LDAP的用户认证类. public class LDAPHelper { private DirectoryEntry _objDirectoryEntry; /// <summary> ...
- cron 定时器简单入门
cron:计划任务,是任务在约定的时间执行已经计划好的工作,根据配置文件约定的时间来执行特定的任务. 编写测试类继承 IJob ,实现Execute 此方法就是用于定时的任务 配置定时时间: 先创建w ...
- webpack使用笔记
webpack简介 CommonJS和AMD是用于JavaScript模块管理的两大规范,前者定义的是模块的同步加载,主要用于NodeJS:而后者则是异步加载,通过requirejs等适用于前端.np ...
- encodeURI来解决URL传递时的中文问题
在AJAX浏览器来进行发送数据时,一般它所默认的都是UTF-8的编码. 使用JQUERY中所提供的方法来做操作 encodeURI function verify() { //解决中文乱麻问题的 ...
- 利用nodejs的cheerio抓取网站数据
/*引入模块*/ var http = require('http') var url = 'http://www.cnblogs.com/txxt' var cheerio = require('c ...