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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Luogu P3369 【模板】普通平衡树

發(fā)布時間:2023/12/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Luogu P3369 【模板】普通平衡树 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Luogu P3369 【模板】普通平衡樹


啊 splay啊

代碼:

#include<cstdio> #include<cstring> #include<algorithm>//左兒子一定比我小 右兒子一定比我大 /* * <----0| * <----rt / \* */ \ / \* * * * 這是一棵樹 */ struct nod1{int ch[2],c,fa,size,cnt;}tr[110010]; //ch[0]是左兒子編號 ch[1]是右兒子比那好 //c是節(jié)點數(shù)值 fa是節(jié)點爸爸 size是以節(jié)點為根子樹大小 //cnt是和節(jié)點數(shù)值一樣的數(shù)的個數(shù) int n,rt,tot; //n是操作數(shù) rt是根 tot是整個數(shù)的節(jié)點個數(shù),添加新節(jié)點時用到 void update(int x)//更新維護 此處x是編號 {tr[x].size=tr[tr[x].ch[0]].size+tr[x].cnt+tr[tr[x].ch[1]].size;//x子樹大小=x左子樹+x右子樹+x節(jié)點相同數(shù)個數(shù) return ; }//okint findip(int x)//找x數(shù)值的節(jié)點編號 此處x是數(shù)值 {int now=rt;//從根開始找 while(x!=tr[now].c){if(x<tr[now].c)//比當(dāng)前點數(shù)值小 {if(tr[now].ch[0]==0)break;//沒有,只好跳出循環(huán) 返回當(dāng)前這個now 是與x最貼切的節(jié)點 now=tr[now].ch[0];//走左邊 }else{if(tr[now].ch[1]==0)break;now=tr[now].ch[1];//走右邊 }}return now; }void add(int c,int x)//添加新節(jié)點 此處c是數(shù)值,x是新節(jié)點爸爸的編號 {tot++;tr[tot].c=c;tr[tot].cnt=1;tr[tot].size=1;tr[tot].fa=x;tr[tot].ch[0]=tr[tot].ch[1]=0;if(c<tr[x].c)tr[x].ch[0]=tot;else tr[x].ch[1]=tot;//判斷新節(jié)點是爸爸的左兒子還是右兒子 return ; }void rotate(int x,int w)//單旋 此處x是編號 w是兒子標(biāo)記 w等于1意味著我是我爸的左兒子,否則為我爸的右兒子 {int f=tr[x].fa,ff=tr[f].fa;tr[f].ch[1-w]=tr[x].ch[w];//這里的ch[0]是左兒子,ch[1]是右兒子//如果我是我爸的右兒子,那么說明我的整棵子樹都比他大,所以我的左兒子給我爸當(dāng)右兒子//如果我是我爸的左兒子,那么說明我的整棵子樹都比他小,所以我的右兒子給我爸當(dāng)左兒子if(tr[x].ch[w]!=0)tr[tr[x].ch[w]].fa=f; if(tr[ff].ch[0]==f)tr[ff].ch[0]=x;//爺爺>爸爸 else tr[ff].ch[1]=x;//爸爸是爺爺什么兒子 我旋轉(zhuǎn)后就給爺爺當(dāng)什么兒子 tr[x].fa=ff;tr[f].fa=x;tr[x].ch[w]=f;update(f);//更新底層 update(x);//更新當(dāng)前層 }void splay(int x,int goal)//把x旋到目標(biāo)節(jié)點下面 {while(tr[x].fa!=goal){int f=tr[x].fa,ff=tr[f].fa;if(ff==goal)//爺爺就是目標(biāo){//旋一次就行 if(x==tr[f].ch[0])//我<我爸 rotate(x,1);else rotate(x,0);} else{if(tr[ff].ch[0]==f)//爺爺>我爸 {if(tr[f].ch[0]==x)//我爸>我 {//我與我爸共線 則雙旋rotate(f,1);//我爸是我爺爺左兒子 rotate(x,1);//我是我爸左兒子 }else{//我爸<我 rotate(x,0);//我是我爸右兒子 rotate(x,1);//現(xiàn)在我是我爺爺左兒子}} else//爺爺<我爸 { if(tr[f].ch[0]==x){rotate(x,1);//我是我爸左兒子 rotate(x,0);//現(xiàn)在我是我爺爺右兒子 }else{//我與我爸共線 則雙旋rotate(f,0);//我爸是我爺爺右兒子 rotate(x,0);//我是我爸右兒子 }}} }if(goal==0)rt=x; }void insert(int x)//插入一個數(shù) 此處x是數(shù)值 {if(rt==0){//第一個節(jié)點 先讓你當(dāng)0兒子 add(x,0);rt=tot;return ;}int ip=findip(x);//找出x數(shù)值的節(jié)點編號或是最貼近的節(jié)點 if(tr[ip].c==x){//之前插入過這個數(shù)值 tr[ip].cnt++;update(ip);splay(ip,0);}else{add(x,ip);//新點 update(ip);splay(tot,0);} }void del(int x)//刪除一個數(shù) 此處x是數(shù)值 {int ip=findip(x);//拿它編號 splay(ip,0);//讓它當(dāng)根 方便操作 if(tr[ip].c!=x)return ;//之前沒有插入過這個數(shù)值 if(tr[ip].cnt>1){//不止一個這個數(shù)值 tr[ip].cnt--;update(ip);}else if(tr[ip].ch[0]==0&&tr[ip].ch[1]==0)//已經(jīng)將這個點旋到根了 如果沒有左右兒子 說明整棵樹只有一個點 rt=0,tot=0;else if(tr[ip].ch[0]!=0&&tr[ip].ch[1]==0)//只有一個兒子就讓他繼承 rt=tr[ip].ch[0],tr[tr[ip].ch[0]].fa=0;else if(tr[ip].ch[1]!=0&&tr[ip].ch[0]==0)//只有一個兒子就讓他繼承 rt=tr[ip].ch[1],tr[tr[ip].ch[1]].fa=0;else{int p=tr[ip].ch[0];while(tr[p].ch[1]!=0)p=tr[p].ch[1];//找前驅(qū)來 splay(p,ip);//旋到我這里來,因為前驅(qū)是小于我中最大的 它此時沒有右兒子 rt=p;tr[p].fa=0;tr[tr[ip].ch[1]].fa=p;//直接把右兒子給它 tr[p].ch[1]=tr[ip].ch[1];update(p);} }int rank(int x)//此處x是數(shù)值 找出x的排名 {int ip=findip(x);splay(ip,0);//把我旋成根 方便處理 return tr[tr[ip].ch[0]].size+1;//我是根 所以左子樹全小于我 +1就是我排名 }int kth(int x)//找排名是x的數(shù)值 {int now=rt;while(1){if(x<=tr[tr[now].ch[0]].size)//如果我小于左邊的個數(shù) 去左邊找 now=tr[now].ch[0];else if(tr[tr[now].ch[0]].size+tr[now].cnt<x){//如果比左+當(dāng)前自己還大 去右邊 x=x-tr[tr[now].ch[0]].size-tr[now].cnt;now=tr[now].ch[1];} else break;//等于當(dāng)前 }return tr[now].c; }int last(int x)//找前驅(qū) 此處x是數(shù)值 {int ip=findip(x);splay(ip,0);if(x<=tr[ip].c&&tr[ip].ch[0]!=0){ip=tr[ip].ch[0];while(tr[ip].ch[1]!=0)ip=tr[ip].ch[1];} //比我小最大的:左子樹最右的 if(x<=tr[ip].c)return 0;return tr[ip].c; }int next(int x)//找后繼 此處x是數(shù)值 {int ip=findip(x);splay(ip,0);if(x>=tr[ip].c&&tr[ip].ch[1]!=0){ip=tr[ip].ch[1];while(tr[ip].ch[0]!=0)ip=tr[ip].ch[0]; } //比我大最小的:右子樹最左邊if(x>=tr[ip].c)return 0;return tr[ip].c; }int main() {scanf("%d",&n);for(int i=1;i<=n;i++){int h,x;scanf("%d %d",&h,&x);if(h==1)insert(x);else if(h==2)del(x);else if(h==3)printf("%d\n",rank(x));else if(h==4)printf("%d\n",kth(x));else if(h==5)printf("%d\n",last(x));else if(h==6)printf("%d\n",next(x));} }

看了好多博客 要昏了

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。