伸展树
学习的博客
网址:http://dongxicheng.org/structure/splay-tree/
http://blog.csdn.net/acm_cxlove/article/details/7815019
http://blog.csdn.net/leolin_/article/details/6436037
数组版 http://code.bulix.org/w8s75i-81022
伸展操作:
//旋转操作 0表示左旋 1表示右旋 void Rotate(int x,int kind) { int y = pre[x]; pushdown(y); pushdown(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y] = x; pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; pushup(y); } //将rt结点调整到goal void splay(int rt,int goal) { pushdown(rt); while(pre[rt] != goal) { if(pre[pre[rt]] == goal){ Rotate(rt,ch[pre[rt]][0]==rt); } else { int y = pre[rt]; int kind = (ch[pre[y]][0]==y); if(ch[y][kind] == rt){ Rotate(rt,!kind); Rotate(rt,kind); } else { Rotate(y,kind);//因为这里是要转到根结点 Rotate(rt,kind); } } } pushup(rt); if(goal == 0) root = rt; }
这样操作过后,又有平衡树的优点,可以进行旋转,又有线段树的优点,能够找到区间询问操作。
如果要删除[l,r]区间,只要将l-1的结点调整到根,然后找到r结点,直接将根结点的有孩子连到r+1即可。
void Get_interval(int l,int r) { //Get_kth()为找到第k个结点 splay(Get_kth(l-1),0);//将l-1的结点调整为根结点 splay(Get_kth(r+1),root);//将r+1的结点调整为根结点的孩子 //这样根的右孩子的左子树就是区间[l,r] pushup(ch[root][1]);//更新根节点的有孩子 pushup(root);//更新根节点 }
这个函数便可以很快找到区间[l,r]执行之后的根的右孩子的左子树便是所要区间
伸展树也可以完成线段树的一些工作,也可以设置延迟标记,向上更新,向下更新等等
专题:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=104277#overview 密码:laomei123
E:http://www.cnblogs.com/sweat123/p/5138338.html
G:http://www.cnblogs.com/sweat123/p/5141435.html
H:http://www.cnblogs.com/sweat123/p/5135018.html
J:http://www.cnblogs.com/sweat123/p/5181799.html