日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【洛谷P3369】普通平衡树(splay)

發布時間:2025/5/22 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【洛谷P3369】普通平衡树(splay) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

emmmmm直接丟代碼了

#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<set> #include<map> #include<queue> #include<algorithm> #include<vector> #include<cstdlib> #include<cmath> #include<ctime> #include<stack> #define ri register int using namespace std; const int mx = 100000 + 5; struct in {int sz,cnt,v;in *ch[2],*f;void su()//統計大小 {sz = ch[0] -> sz + ch[1] -> sz + cnt;}int dir()//判斷自己為左/右蛾子 {return f -> ch[1] == this;}int cmp(int x)//判斷該向哪里走 {if(v == x)return -1;return x > v;}void setc(in *p,int d)//把這棵子樹接到另一個點上 {(ch[d] = p) -> f = this;} }T[mx],*root,*null,*Null; int tot; in* newnode(in *p,int x)//建立新節點 {in *qwq = &T[++ tot];qwq -> v = x,qwq -> f = p,qwq -> cnt = qwq -> sz = 1;qwq -> ch[0] = qwq -> ch[1] = Null;return qwq; } void rotate(in *p)//旋轉 {in *fa = p -> f;int d = p -> dir();//判斷旋轉方向:d^1 fa -> f -> setc(p,fa -> dir());//先把p接到它父親的位置上 fa -> setc(p -> ch[d ^ 1],d),fa -> su();//然后把這個多出來的蛾子接到原來p在fa的位置上 p -> setc(fa,d ^ 1),p -> su();//最后把fa接在d^1這邊 if(root == fa)//判斷是不是更新根節點 root = p; } void splay(in *p,in *rt) {if(rt == p)return ;while(p -> f != rt){if(p -> f -> f == rt){rotate(p);break;}else{if(p -> dir() == p -> f -> dir())//如果同方向,先旋轉父親,再旋轉本身 rotate(p -> f),rotate(p);else//否則一直旋轉本身 rotate(p),rotate(p);}}p -> su();if(rt == null)//如果發現這個點被要求旋轉到樹根,則更新樹根 root = p; } void insert(in *p,int x)//插入 {if(root == Null)//如果一個點都沒有 {root = newnode(null,x);return;//null是樹根,Null是空的意思 }while(p -> ch[p -> v < x] != Null)//不停的走,x偏小向左,偏大向右,與該點相等停下 {if(p -> v == x)break;p = p -> ch[p -> v < x];}if(p -> v == x)//判斷下是不是與該點相等 {p -> sz ++,p -> cnt ++,splay(p,null);return;}p -> ch[p -> v < x] = newnode(p,x);//建新點 splay(p -> ch[p -> v < x],null);//只要是插入刪除就splay一下維持平衡 } in* find(int x)//查找一個點并返回它的位置 {in *rt = root;while(rt -> ch[x > (rt -> v)] != Null && x != (rt -> v))rt = rt -> ch[x > (rt -> v)];return rt; } in* next(int x,bool flag)//查找前驅后繼 {in *rt = root,*qwq;int re;if(!flag)//前驅 {re = 0;while(rt -> ch[0]||rt -> ch[1]){if(rt -> v >= x){if(rt -> ch[0] != Null)//太大向左走 rt = rt -> ch[0];elsebreak;}else{if(rt -> v > re)//選取盡可能和x接近的數 re = rt -> v,qwq = rt;if(rt -> ch[1] != Null)//太小向右走 rt = rt -> ch[1];elsebreak; }}if(rt -> v < x && rt -> v > re)//與最后到達的點進行比較 re = rt -> v,qwq = rt;}else//后繼,與前驅原理類似 {re = 1000000007;while(rt -> ch[0]||rt -> ch[1]){if(rt -> v <= x){if(rt -> ch[1] != Null)rt = rt -> ch[1];elsebreak;}else{if(rt -> v < re)re = rt -> v,qwq = rt;if(rt -> ch[0] != Null)rt = rt -> ch[0];elsebreak; }}if(rt -> v > x && rt -> v < re)re = rt -> v,qwq = rt;}return qwq; } void erase(int x)//刪除 {in *rt = find(x);//先找到這個點 if(rt -> cnt > 1)//如果這個點上的數出現了很多次,就cnt-- {rt -> sz --,rt -> cnt --,splay(rt,null);return;}//否則把這個點徹底刪除掉 bool k = rt -> f -> ch[1] == rt;//判斷該點是右蛾子還是左蛾子 if(rt -> ch[0] == Null)if(rt -> ch[1] ==Null)//啥蛾子沒有就直接刪掉這個點 rt -> f -> ch[k] = Null;else//如果只有一個蛾子就讓它代替被刪除點的位置 rt -> f -> ch[k] = rt -> ch[1],rt -> ch[1] -> f = rt -> f;elseif(rt -> ch[1] == Null)rt -> f -> ch[k] = rt -> ch[0],rt -> ch[0] -> f = rt -> f;else//否則如果左右蛾子都有的話 ,就讓左蛾子頂替位置,然后把右蛾子放到左蛾子子樹的最靠上的右空位(因為右蛾子的任何一個點都比做蛾子大,肯定在這棵子樹的最右邊) {in *ls = rt -> ch[0];rt -> f -> ch[k] = rt -> ch[0];rt -> ch[0] -> f = rt -> f;while(ls -> ch[1] != Null)ls = ls -> ch[1];ls -> ch[1] = rt -> ch[1];rt -> ch[1] -> f =ls;ls -> su(),splay(ls,null);}rt -> f -> su();splay(rt -> f,null); } int ask(int x)//查找一個數的排名,利用二叉搜索樹本身左小右大的性質 {if(root == Null)return 0;in *rt = root;int re = 0;while(rt -> v != x)//直到找到這個數為止 {bool fl = x > rt -> v;if(fl == 1)re += rt -> ch[0] -> sz + rt -> cnt;rt = rt -> ch[fl];}re += rt -> ch[0] -> sz + 1;//最后記錄下左子樹的大小然后再加上它本身 splay(rt,null);return re; } int ask1(int x)//查找排x位的數 {in *rt = root;int num = rt -> ch[0] -> sz;while(!(x > num && x <= num + rt -> cnt))//括號里面表達式的意思為恰好找到排名為k的時候 {if(x > num)//如果大于左子樹,向右走,減去左側排名 x -= num + rt -> cnt,rt = rt -> ch[1];else//否則向左走 rt = rt -> ch[0];num = rt -> ch[0] -> sz;}splay(rt,null);return rt -> v; } int n,opt,xx; int main() {Null = root = &T[++ tot],null = &T[++ tot],null -> ch[0] = null -> ch[1] = Null;//Null是為了初始賦值,null是根節點 scanf("%d",&n);while(n --){scanf("%d%d",&opt,&xx);if(opt == 1)insert(root,xx);//插入 if(opt == 2)erase(xx);//刪除 if(opt == 3)printf("%d\n",ask(xx));//查詢x的排名 if(opt == 4)printf("%d\n",ask1(xx));//查詢排名為x的數 if(opt == 5)printf("%d\n",next(xx,0) -> v);//前驅 if(opt == 6)printf("%d\n",next(xx,1) -> v);//后繼 } }

?

轉載于:https://www.cnblogs.com/Loi-dfkdsmbd/p/8449498.html

總結

以上是生活随笔為你收集整理的【洛谷P3369】普通平衡树(splay)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。