UVA 11922 伸展树Splay 第一题
上次ZOJ月赛碰到一个题目要求对序列中的某个区间求gcd,并且还要随时对某位数字进行修改 插入 删除,当时马上联想到线段树,但是线段树不支持增删,明显还是不可以的,然后就敲了个链表想暴力一下,结果TLE。那天回来后搜了下题解,发现大家都在说平衡树 Splay,就好好学了下,这玩意还是挺难学的,我看了好久。最后还是从网上找了三篇论文打印了下,趁着TCG讲数据库的时候(这课真的好催眠)好好看了下,才搞清楚基本的Splay操作
这是第一道Splay题目,基本上是照着模板敲出来的,没办法,第一次学,好多地方不熟练,不过整个过程我已经形成了一个条理了,这倒是一大收获
由于自己的粗心,好几个细节错了,调试了好久。。Sigh!
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 150010
using namespace std;
struct Node
{
Node *ch[],*pre;
int val,size;
bool rev;
void update()
{
size=ch[]->size+ch[]->size+;
}
void pushdown();
}Tnull,*null=&Tnull;//这里要把null设置为指针,由于下面基本上用的指针,有大量判断是否相等,必须统一类型。
void Node::pushdown()//该函数涉及null,不能写在结构体里,否则被认为null未被定义,只能用写在外面这样的方式来实现
{
if (rev){
swap(ch[],ch[]);
for (int i=;i<;i++)
if (ch[i]!=null) ch[i]->rev=!ch[i]->rev;
rev=;
}
}
Node nodePool[N];
Node *root,*cur;
int n,m;
Node * newNode(int v,Node* f) //从点池中生成新的点
{
cur->ch[]=cur->ch[]=null;
cur->size=;
cur->val=v;
cur->rev=;
cur->pre=f;
return cur++;
}
Node*build(int l,int r,Node* f)//建树操作。
{
if (l>r) return null;
int mid=(l+r)>>;
//printf("%d %d\n",l,r);
Node* temp=newNode(mid,f);
temp->ch[]=build(l,mid-,temp);
temp->ch[]=build(mid+,r,temp);
temp->update();
return temp; }
void rotate(Node* x,int c) //旋转操作,分情况讨论下就行
{
Node* y=x->pre;
y->pushdown();
x->pushdown();
// puts("judge1");
y->ch[!c]=x->ch[c];
if (x->ch[c]!=null)
x->ch[c]->pre=y;
x->pre=y->pre;
// puts("judge2");
if (y->pre!=null){
// puts("deep1");
//if (y->pre==null) puts("Yes");
//printf("%d\n",y->pre->size);
if (y->pre->ch[]==y){
//puts("deep2"); y->pre->ch[]=x;
// puts("deep3");
}
else{
// puts("deep4");
y->pre->ch[]=x;
// puts("deep5");
}
}
// puts("judge3");
x->ch[c]=y;
y->pre=x;
y->update();
x->update();
if (y==root)
root=x;
//puts("is there?");
}
void Splay(Node* x,Node* f)//Splay过程说白了就是把x节点旋转到f下面,分情况讨论一下就可以
{
x->pushdown();
while (x->pre!=f)
{
//puts("Why?");
if (x->pre->pre==f)
{
if (x->pre->ch[]==x)
rotate(x,);
else
rotate(x,);
// puts("pass1");
}
else
{
//puts("pass2");
Node *y=x->pre;
Node *z=y->pre;
if (z->ch[]==y)
{
// puts("pass3");
if (y->ch[]==x)
rotate(y,),rotate(x,);
else
rotate(x,),rotate(x,);
// puts("pass4");
}
else
{
// puts("pass5");
//rotate(y,1);
if (y->ch[]==x){
// puts("pass6");
rotate(x,);
rotate(x,);
//puts("pass7");
}
else
{
// puts("pass8");
rotate(y,),rotate(x,);
}
// puts("pass10");
}
//puts("pass7");
}
// puts("isblock?");
}
x->update();
}
void select(int k,Node* f) //把第k个节点旋转到f的下面
{
int tmp;
Node* x=root;
//x->pushdown();
k++; //因为建树的时候插入了0点作为缓冲点,因此实际的点要++以消除该点的影响。
for (;;){
x->pushdown();
tmp=x->ch[]->size;
if (k==tmp+) break;
if (k<=tmp)
x=x->ch[];
else{
k-=tmp+;
x=x->ch[];
}
}
//puts("Test");
Splay(x,f);
// puts("t");
}
Node* get(int l,int r)
{
select(l-,null);
//puts("pass");
select(r+,root);
// puts("pass");
return root->ch[]->ch[];
}
void reverses(int a,int b) //翻转操作
{
Node* o=get(a,b);
//puts("Pass");
o->rev=!o->rev;
Splay(o,null); }
void split(int l,int r,Node* &s)//切除翻转序列,并把切除的序列用s保存起来
{
Node*temp=get(l,r);
root->ch[]->ch[]=null;
root->ch[]->update();
root->update();
s=temp;
}
void cut(int l,int r) //把切除的序列接到序列末端,只需把序列的最右边点移到根节点,再设置它的右孩子为刚刚切除的序列即可
{
Node *tmp;
split(l,r,tmp);
select(root->size-,null);//把自己手动设置的第n+1点移植到顶点,这样做的原因是防止他干扰,不移它的话,最右点就不是第n点,而是n+1点了
select(root->size-,root);
root->ch[]->ch[]=tmp;
tmp->pre=root->ch[];
root->ch[]->update();
root->update();
}
void init(int num)
{
cur=nodePool;
root=null;
root=newNode(,null);
root->ch[]=newNode(num+,root);//设置两个缓冲点,我刚刚还在犹豫n+1点是否需要,经实测确实需要,因为程序中随时要探测自己的子孩子,如果不设置,可能会溢出
root->ch[]->ch[]=build(,num,root->ch[]);
root->update();//
}
void output()
{
for (int i=;i<=n;i++)
{
select(i,null); //输出某点即把该点旋转到根节点再输出
printf("%d\n",root->val);
}
}
int main()
{
int a,b;
while (scanf("%d%d",&n,&m)!=EOF)
{
init(n);
//output();
while (m--)
{
scanf("%d%d",&a,&b);
if (a>b) swap(a,b);
reverses(a,b);
cut(a,b);
}
output();
}
}
UVA 11922 伸展树Splay 第一题的更多相关文章
- ZOJ 3765 Lights (zju March I)伸展树Splay
ZJU 三月月赛题,当时见这个题目没辙,没学过splay,敲了个链表TLE了,所以回来好好学了下Splay,这道题目是伸展树的第二题,对于伸展树的各项操作有了更多的理解,这题不同于上一题的用指针表示整 ...
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- UVA 11922 Permutation Transformer —— splay伸展树
题意:根据m条指令改变排列1 2 3 4 … n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘 ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- 伸展树Splay【非指针版】
·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...
- POJ 3580 - SuperMemo - [伸展树splay]
题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...
随机推荐
- Spark 下操作 HBase(1.0.0 新 API)
hbase1.0.0版本提供了一些让人激动的功能,并且,在不牺牲稳定性的前提下,引入了新的API.虽然 1.0.0 兼容旧版本的 API,不过还是应该尽早地来熟悉下新版API.并且了解下如何与当下正红 ...
- 用JS改变embed标签的src属性
思路: A.先隐藏embed标签 B.清除embed元素 C.为embed重新赋值,加入Html页面中 1.html代码 <object id="forfun" classi ...
- C++实现单链表的12种基本操作
C++单链表的操作2017-12-25 1 // 单链表.cpp: 定义控制台应用程序的入口点. //Author:kgvito //Date: 2017.12.25 #include "s ...
- mysql怎么查看当前登录用户
mysql> select user();+----------------+| user() |+----------------+| root@localhost |+--- ...
- 二十七、SAP中通过以字段的形式输出内容
一.输出时,需要加入关键词sy-vline,代码如下 二.效果如下
- 162-PHP 文本替换函数str_replace(三)
<?php $str='Hello world!'; //定义源字符串 $search=array('o','l','w'); //定义将被替换的字符数组 $replace='O'; //定义替 ...
- 094-PHP遍历索引数组和关联数组
<?php $arr=array(63,'abc',45,'hello',3,7,9,'DEF'); //定义一个索引数组 echo '遍历一个索引数组:<br />'; forea ...
- nui UI 具有右键属性的菜单树
参考示例:树右键菜单 一:创建ContextMenu <ul id="treeMenu" class="nui-contex ...
- Petr#(字符串哈希)
CF113B Petr# 大概就是字符串匹配加一个字符串哈希判重.懒得打kmp,就用字符串哈希匹配了. 字符串哈希大概就是把字符串转成一个p进制的数,每一段字符串都有一个对应的哈希值.p尽量取质数,这 ...
- Ubuntu Vi指令
Ubuntu在不更新源的情况下是没办法使用Vim指令的只能使用Vi指令 所有我也就记录了下来 vi / vim命令: 插入内容: i: 插入光标前一个字符 I: 插入行首 a: 插入光标后一个字符 A ...