洛谷P3391文艺平衡树(Splay)
生活随笔
收集整理的這篇文章主要介紹了
洛谷P3391文艺平衡树(Splay)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目傳送門
轉載自https://www.cnblogs.com/yousiki/p/6147455.html,轉載請注明出處
經典引文
空間效率:O(n) 時間效率:O(log n)插入、查找、刪除 創造者:Daniel Sleator 和 Robert Tarjan優點:每次查詢會調整樹的結構,使被查詢頻率高的條目更靠近樹根。
Tree Rotation
? 樹的旋轉是splay的基礎,對于二叉查找樹來說,樹的旋轉不破壞查找樹的結構。 ?
Splaying
? Splaying是Splay Tree中的基本操作,為了讓被查詢的條目更接近樹根,Splay Tree使用了樹的旋轉操作,同時保證二叉排序樹的性質不變。 Splaying的操作受以下三種因素影響:- 節點x是父節點p的左孩子還是右孩子
- 節點p是不是根節點,如果不是
- 節點p是父節點g的左孩子還是右孩子
Zig Step
當p為根節點時,進行zip step操作。 當x是p的左孩子時,對x右旋; 當x是p的右孩子時,對x左旋。 ?
Zig-Zig Step
當p不是根節點,且x和p同為左孩子或右孩子時進行Zig-Zig操作。 當x和p同為左孩子時,依次將p和x右旋; 當x和p同為右孩子時,依次將p和x左旋。 ? ?Zig-Zag Step
當p不是根節點,且x和p不同為左孩子或右孩子時,進行Zig-Zag操作。 當p為左孩子,x為右孩子時,將x左旋后再右旋。 當p為右孩子,x為左孩子時,將x右旋后再左旋。 ? ?應用
? Splay Tree可以方便的解決一些區間問題,根據不同形狀二叉樹中序遍歷結果不變的特性,可以將區間按順序建二叉查找樹。 每次自下而上的一套splay都可以將x移動到根節點的位置,利用這個特性,可以方便的利用Lazy的思想進行區間操作。 對于每個節點記錄size,代表子樹中節點的數目,這樣就可以很方便地查找區間中的第k小或第k大元素。 對于一段要處理的區間[x, y],首先splay x-1到root,再splay y+1到root的右孩子,這時root的右孩子的左孩子對應子樹就是整個區間。 這樣,大部分區間問題都可以很方便的解決,操作同樣也適用于一個或多個條目的添加或刪除,和區間的移動。?
最后附上自己寫的洛谷的模板題的代碼:
?
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,root,tot; struct Node{int ch[2],size;int fa,mark,val;void add(int x,int y){ch[0]=ch[1]=mark=0;val=x;fa=y;size=1;} }t[N]; inline int read() {char ch=getchar();int num=0;bool flag=false;while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}return flag?-num:num; } inline void pushup(int x) {int l=t[x].ch[0],r=t[x].ch[1];t[x].size=t[l].size+t[r].size+1; } inline void pushdown(int x) {if(t[x].mark){t[t[x].ch[0]].mark^=1;t[t[x].ch[1]].mark^=1;swap(t[x].ch[0],t[x].ch[1]);t[x].mark=0;} } inline void rotate(int x) {int y=t[x].fa;int z=t[y].fa;int k=(t[y].ch[1]==x);t[z].ch[t[z].ch[1]==y]=x;t[x].fa=z;t[t[x].ch[k^1]].fa=y;t[y].ch[k]=t[x].ch[k^1];t[x].ch[k^1]=y;t[y].fa=x;pushup(y);pushup(x); } inline void splay(int x,int tag) {while(t[x].fa!=tag){int y=t[x].fa;int z=t[y].fa;if(z!=tag)(t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x):rotate(y);rotate(x);}if(tag==0)root=x; } inline void insert(int x) {int now=root,fa=0;while(now)fa=now,now=t[now].ch[x>t[now].val];now=++tot;if(fa)t[fa].ch[x>t[fa].val]=now;t[now].add(x,fa);splay(now,0); } inline int find(int x) {int now=root;while(555){pushdown(now);if(t[t[now].ch[0]].size>=x)now=t[now].ch[0];else if(t[t[now].ch[0]].size+1==x)return now;else x-=(t[t[now].ch[0]].size+1),now=t[now].ch[1];} } inline void work(int l,int r) {l=find(l);r=find(r+2);splay(l,0);splay(r,l);t[t[t[root].ch[1]].ch[0]].mark^=1; } inline void print(int x) {pushdown(x);if(t[x].ch[0])print(t[x].ch[0]);if(t[x].val>1&&t[x].val<n+2)printf("%d ",t[x].val-1);if(t[x].ch[1])print(t[x].ch[1]); } int main() {n=read();m=read();for(int i=1;i<=n+2;i++)insert(i);for(int i=1;i<=m;i++){int l=read();int r=read();work(l,r);}print(root);return 0; }?
?
?
?
?
轉載于:https://www.cnblogs.com/cytus/p/8252154.html
總結
以上是生活随笔為你收集整理的洛谷P3391文艺平衡树(Splay)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [LeetCode] 67. Add
- 下一篇: js中怎么为同级元素添加点击事件