调Splay太恐怖了,虽然不难,但是为什么bug这么多。。。这里记一下原则性问题吧。。。
类名叫SplayTree
int v,size;//分别是键值,子树大小, bool pl;//place 表示该节点在父节点的哪个位置 ST *pr,*suc[2],*Nil;//分别表示前驱,两个后继,和Nil节点的位置
/*由于SpayTree太长了,一下所写为ST*/ void mt();//maintain 即维护Splay,保证信息的正确性 void ini();//初始化,将所有的前驱后继都改成Nil void trans(ST *tar,bool place);//将该子树移动到tar的place边(place=0表示左子树,反之右子树) void rotate();//旋转,一个函数搞定左旋/右旋 void Splay();//核心操作,即将某节点提到根 ST *find_v(int fv)//找到fv所在的位置,找不到返回它应该在的位置的根(按照数字值查询) void insert(int iv/*也可以是 ST*p */);//插入iv到相应位置 void find_s(int pos);//按照size找第pos小的元素,也就是如果要求第pos小的元素是哪个,就可以用这个函数在O(lgn)的时间复杂度内完成 ST *fmin/*或fmax*/();//找到最小值所在的位置(返回指针) void merge(ST *obj);//将obj所在的Splay合并到该节点所在的Splay...
void trans(ST *tar,bool place){//ST::移形换位 pl=place; pr=tar; tar->suc[pl]=this; } void rotate(){//旋转 bool ppl=pl; ST fprev=*pr; suc[!pl]->trans(pr,pl);//移动子树 pr->trans(this,!pl);//移动原前驱 trans(fprev.pr,fprev.pl);//移动该节点 suc[!ppl]->mt(); mt(); } void Splay(){//Splay操作 while(pr!=Nil){ if(pl==pr->pl && pr->pr!=Nil) pr->rotate(); rotate(); } }
中午的时候突然想起NOI2005的维护序列,于是就写了8小时搞出来,3小时写,5小时调,效率真够低的...
这是个很麻烦的问题,我用Splay解决的,首先题目要求的操作有6种,
其中翻转,求最大和比较麻烦.
Splay的两个维护函数:deliver()和maintain()
deliver()负责传递树根信息(翻转和MakeSame)
maintain()负责维护Splay的正确性(重新计算相关信息如Sum,LMax...)
我写了6K的代码,花了我很长的时间,然而并没有结束,因为明天还有继续优化代码和算法结构,以便下次再遇到能很快的写出.