很神奇的旋转操作。

目前没看到其他数据结构能实现这个功能。平衡树不好处理区间操作,线段树很难旋转。splay tree搞这个就很简单了。

下面用的这个模板跑了700ms,好慢,估计是删除操作太费时了,是时候去找找其他更快的模板了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std; #define MAXN 100100 //好慢啊 优化下
bool Add[MAXN];//延迟标记 struct Splay_Tree
{
int cnt, rt;//cnt为节点数,rt == root struct Tree{
int key;//关键字
int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。
int fa, son[];
}T[MAXN]; inline void init()
{
cnt = ;//初始化超级根节点(标记为0的节点)
T[].size = ;
rt = ;
memset(Add,,sizeof(Add));//开始初始化0
}
inline void PushUp(int x)
{
T[x].size=T[T[x].son[]].size+T[T[x].son[]].size+T[x].num;
} inline void PushDown(int x)
{
//翻转操作,这一步最为关键
if(Add[x])
{
if(T[x].son[])//
{
int son0 = T[x].son[];
//不管那么多,先旋转起来。
swap(T[son0].son[],T[son0].son[]);
Add[son0] ^= ;
}
if(T[x].son[])
{
int son1 = T[x].son[];
//不管那么多,先旋转起来。
swap(T[son1].son[],T[son1].son[]);
Add[son1] ^= ;
}
Add[x]=;//不管子节点有没有,这层一定往下推,没有子节点相当于标记无效。
}
} inline int Newnode(int key, int fa) //新建一个节点并返回
{
++cnt;
T[cnt].key=key;
T[cnt].num=T[cnt].size=;
T[cnt].fa=fa;
T[cnt].son[]=T[cnt].son[]=;
return cnt;
} inline void Rotate(int x, int p) //0左旋 1右旋
{
int y=T[x].fa;
PushDown(y);//你是说这个有问题。
PushDown(x);
T[y].son[!p]=T[x].son[p];
T[T[x].son[p]].fa=y;
T[x].fa=T[y].fa;
if(T[x].fa)
T[T[x].fa].son[T[T[x].fa].son[] == y]=x;
T[x].son[p]=y;
T[y].fa=x;
PushUp(y);
PushUp(x);
} void Splay(int x, int To) //将x节点移动到To的子节点中
{
while(T[x].fa != To)
{ if(T[T[x].fa].fa == To)
{
//在这里面得
PushDown(T[x].fa);
PushDown(x);
Rotate(x, T[T[x].fa].son[] == x);
}
else
{
int y=T[x].fa, z=T[y].fa;
PushDown(z);
PushDown(y);
PushDown(x);
int p=(T[z].son[] == y);
if(T[y].son[p] == x)
Rotate(x, !p), Rotate(x, p); //之字旋
else
Rotate(y, p), Rotate(x, p); //一字旋
}
}
if(To == ) rt=x;
} int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
{
if(!rt || p > T[rt].size) return ;
int x=rt;
while(x)
{
PushDown(x);
if(p >= T[T[x].son[]].size+ && p <= T[T[x].son[]].size+T[x].num)
break;
if(p > T[T[x].son[]].size+T[x].num)
{
p-=T[T[x].son[]].size+T[x].num;
x=T[x].son[];
}
else
x=T[x].son[];
}
Splay(x, );
return x;
} int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
{
if(!rt) return ;
int x=rt;
while(x)
{
PushDown(x);
if(T[x].key == key) break;
x=T[x].son[key > T[x].key];
}
if(x) Splay(x, );
return x;
} int Prev() //返回根节点的前驱 非重点
{
if(!rt || !T[rt].son[]) return ;
int x=T[rt].son[];
while(T[x].son[])
{
PushDown(x);
x=T[x].son[];
}
Splay(x, );
return x;
} int next() //返回根结点的后继 非重点
{
if(!rt || !T[rt].son[]) return ;
int x=T[rt].son[];
while(T[x].son[])
{
PushDown(x);
x=T[x].son[];
}
Splay(x, );
return x;
} void Insert(int key) //插入key值
{
if(!rt)
rt=Newnode(key, );
else
{
int x=rt, y=;
while(x)
{
PushDown(x);
y=x;
if(T[x].key == key)
{
T[x].num++;
T[x].size++;
break;
}
T[x].size++;//既然一定调整
x=T[x].son[key > T[x].key];
}
if(!x)
x = T[y].son[key > T[y].key] = Newnode(key, y);
Splay(x, );
}
} void Delete(int key)
{
//我知道什么错误了,删除一个节点前,需要先将这个点splay 到根
int x = key;
if(!x) return;
Splay(x, );
if(T[x].num>)
{
T[x].num--;
PushUp(x);
return;
}
int y=T[x].son[];
PushDown(y);
//终于找到了,只要往下找就得pushdown
while(T[y].son[])
{
y=T[y].son[];
PushDown(y);
}
int z=T[x].son[];
PushDown(z);
while(T[z].son[])
{
z=T[z].son[];
PushDown(z);
}
if(!y && !z)
{
rt=;
return;
}
if(!y)
{
Splay(z, );
T[z].son[]=;
PushUp(z);
return;
}
if(!z)
{
Splay(y, );
T[y].son[]=;
PushUp(y);
return;
}
Splay(y, );
Splay(z, y);//前驱和后继相同是什么鬼
T[z].son[]=;
PushUp(z);
PushUp(y);
} // int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<
// {
// //我没有写PUSH_UP 和 PUSH_DOWN
// if(!rt) return 0;
// int x=rt, ret=0, y=0;
// while(x)
// {
// y=x;
// if(T[x].key <= key)
// {
// ret += T[T[x].son[0]].size + T[x].num;
// x=T[x].son[1];
// }
// else
// x=T[x].son[0];
// }
// Splay(y, 0);
// return ret;
// } // 这个删除太丑了
// void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r
// {
// if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤
// int p=Prev();
// if(!Find(r)) Insert(r);
// int q=next();
// if(!p && !q)
// {
// rt=0;
// return;
// }
// if(!p)
// {
// T[rt].son[0]=0;
// PushUp(rt);
// return;
// }
// if(!q)
// {
// Splay(p, 0);
// T[rt].son[1]=0;
// PushUp(rt);
// return;
// }
// Splay(p, q);
// T[p].son[1]=0;
// PushUp(p);
// PushUp(q);
// } void display(int x)
{
if(x==) return ;
PushDown(x);
display(T[x].son[]);
//printf("%d ",T[x].key);
display(T[x].son[]);
} }spt; struct node
{
int key;
int id;
}g[MAXN]; int cmp(node t1,node t2)
{
if(t1.key == t2.key) return t1.id<t2.id;
return t1.key<t2.key;
} int main() {
//SPT 独特的旋转操作!
int n;
//printf("nishi sb?");
while(scanf("%d",&n) && n)
{
spt.init();
for(int i=;i<=n;i++)
{
int tmp;
scanf("%d",&tmp);
g[i].key = tmp;
g[i].id = i;
spt.Insert(i);
//只是默认了,每个数字的id 就是它在splay 中对应的下标
}
//死循环什么鬼。
//printf("nishi sb ma?");
sort(g+,g++n,cmp);
for(int i=;i<=n;i++)//开始旋转
{
//step one 将当前最小的点,移动到树根处
spt.Splay(g[i].id, );
//spt.display(spt.rt);
//printf("\n");
//step two 将整个左子树旋转
int sonid = spt.T[g[i].id].son[];
printf("%d",spt.T[sonid].size+i);
if(i!=n) printf(" ");
if(sonid != )
{
swap(spt.T[sonid].son[],spt.T[sonid].son[]); Add[sonid] ^= ;
}
//这里那里GG了,果真还是这里有问题。
//第一次就删除了两个,不能看
//spt.display(spt.rt);
//printf("\n");
spt.Delete(g[i].id);
//每次操作之后,都把结果打印一遍
//spt.display(spt.rt);
//printf("\n");
}
printf("\n");
}
return ;
}

splay tree旋转操作 hdu 1890的更多相关文章

  1. hdu 1890 Robotic SortI(splay区间旋转操作)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 题解:splay又一高级的功能,区间旋转这个是用线段树这些实现不了的,这题可以学习splay的旋 ...

  2. [AHOI2006]文本编辑器 Splay tree区间操作

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1269 Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个 ...

  3. HDU 1890 Robotic Sort (splay tree)

    Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  4. hdu 1890 Robotic Sort(splay 区间反转+删点)

    题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的sp ...

  5. Splay Tree的删除操作

    Splay Tree的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...

  6. hdu 2871 Memory Control(伸展树splay tree)

    hdu 2871 Memory Control 题意:就是对一个区间的四种操作,NEW x,占据最左边的连续的x个单元,Free x 把x单元所占的连续区间清空 , Get x 把第x次占据的区间输出 ...

  7. HDU 4453 Looploop (伸展树splay tree)

    Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  8. HDU1890 Robotic Sort Splay tree反转,删除

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 题目中涉及数的反转和删除操作,需要用Splay tree来实现.首先对数列排序,得到每个数在数列 ...

  9. HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436 树状数组做法<猛戳> Splay tree的经典题目,有删除和移动操作.首先要离散化 ...

随机推荐

  1. testform

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. 野哥点评了Facebook、Amazon、Google、微软和苹果

    娱乐一下.我们来比較一下4家相似的科技公司的软件政治观. (1)Facebook-诊断:极端自由. Facebook的规模已经非常大了.可他们的行为处事仍然像是一家创业公司.并且到眼下为止似乎也活得挺 ...

  3. FBX导入错误 :ImportFBX Errors:

    原地址:http://www.cnblogs.com/lopezycj/archive/2012/05/16/unity3d_tuchao.html Unity3D吐槽1--FBX导入 Unity3d ...

  4. lodash forIn forOwn 遍历对象属性

    _.forIn(object, [iteratee=_.identity]) 使用 iteratee 遍历对象的自身和继承的可枚举属性. function Foo() { this.a = 1; th ...

  5. 【English】口头禅

    1. Absolutely! 毫无疑问! 2. Adorable! 可爱极了! 3. Amazing! 太神奇了! 4. Anytime! 随时吩咐! 5. Almost! 差不多了! 6. Awfu ...

  6. nginx和Tomcat集成后发生的重定向问题分析和解决

    nginx和Tomcat集成后发生的重定向问题分析和解决 Tomcat前端配置一个HTTP服务器应该是大部分应用的标配了,基本思路就是所有动态请求都反向代理给后端的Tomcat,HTTP服务器来处 理 ...

  7. 在VS2013 IIS Express 添加MIME映射

    打开VS2013返回json提示MIME映射问题 1.在DOS窗口下进入IIS Express安装目录,默认是C:\Program Files\IIS Express,cmd  命令行cd 到 该目录 ...

  8. IOS推送通知測试工具PushMeBaby

    下载了PushMeBaby在xcode5里中不能使用.类库变了.须要加入Carbon.framework库.在引用的地方改成: #include <Carbon/Carbon.h>.程序就 ...

  9. 【转载】checkbox复选框的一些深入研究与理解

    转载来自:原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com] 一.一开始的唠叨最近忙于开发,自淫于项目的一步步完工,心浮躁了.舍近而求远,兵家之大忌. ...

  10. C语言基础(21)-C语言编译过程及GCC参数简介

    任何C语言的编译过程可分为以下三部分: 一.预编译 在C语言中,以#开头的语句又叫预编译指令.预编译主要做以下两件事情: 1.将#include包含的头文件做简单的文本替换: 2.将代码中的注释删除. ...