bzoj3224 Tyvj 1728 普通平衡樹題解--Treap

題面:

Description您需要寫一種數據結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
1. 插入x數
2. 刪除x數(若有多個相同的數,因只刪除一個)
3. 查詢x數的排名(若有多個相同的數,因輸出最小的排名)
4. 查詢排名為x的數
5. 求x的前驅(前驅定義為小于x,且最大的數)
6. 求x的后繼(后繼定義為大于x,且最小的數)Input第一行為n,表示操作的個數,下面n行每行有兩個數opt和x,opt表示操作的序號(1<=opt<=6)Output對于操作3,4,5,6每行輸出一個數,表示對應答案Sample Input101 1064654 11 3177211 4609291 6449851 841851 898516 819681 4927375 493598Sample Output10646584185492737HINT1.n的數據范圍:n<=1000002.每個數的數據范圍:[-2e9,2e9]
View Code

題解:

  今天第一次接觸平衡二叉樹的概念,做了一道模版題,覺得Treap這東西很神奇啊~

顧名思義,Treap=heap+tree,就是把堆和二叉樹結合在了一起。

但是為什么不用一般的二叉樹呢?(為了給我們增大代碼量)不對,是因為普通樹原來是log(n)級別的,但是經過各種insert啊,del啊什么的就可能失去“平衡”,節點集中在一側什么的,結果成了一條長鏈,這就把log(n)的算法變成O(n)級的線性了。

而現在的Treap就是解決這個問題的方法之一。

Treap中的節點在滿足樹的性質(左兒子都小,右兒子都大之類的)的同時,還對每個節點加入了一個“優先級”,并將節點按照堆的性質排序。這里的優先級采用隨機生成的方式,所以節點的左右分布是隨機的,以此保證整棵樹的相對平衡。

那我們怎么樣對這些節點進行堆的排序呢?

這就有一個看起來很厲害的操作了--旋轉

旋轉分為左旋和右旋。當我們某個節點的左兒子優先度大于本節點,就需要進行右旋,右兒子大,就左旋。

二叉左旋
一棵二叉平衡樹的子樹,根是Root,左子樹是x,右子樹的根為RootR,右子樹的兩個孩子樹分別為RLeftChild和RRightChild。則左旋后,該子樹的根為RootR,右子樹為RRightChild,左子樹的根為Root,Root的兩個孩子樹分別為x(左)和RLeftChild(右)。
二叉右旋
一棵二叉平衡樹的子樹,根是Root,右子樹是x,左子樹的根為RootL,左子樹的兩個孩子樹分別為LLeftChild和LRightChild。則右旋后,該子樹的根為RootL,左子樹為LLeftChild,右子樹的根為Root,Root的兩個孩子樹分別為LRightChild(左)和x(右)。

來自百度百科,個人覺得挺容易懂的。

那么問題來了,為什么你這么一轉,還能保持樹的性質成立呢?為什么不會把節點權小的和大的弄返呢?不會把樹弄亂嗎?

這就是旋轉的真正厲害之處了----可以發現,旋轉前后,該子樹的中序遍歷是不變的!就是說并不會改變數列的大小順序。我也不是很懂具體是為什么能這樣,但是確實很厲害。

剩下就沒什么了,樹嘛,插入刪除的都比較基礎。

放代碼:

?

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=100010,inf=100000000;
  4 int cnt,ret,n,t1,t2,root;
  5 struct treap{
  6     int lc,rc,key,pri,siz,val;
  7 /*key是關鍵字(權),pri是優先度,siz為子樹大小,val表示key這個數有幾個*/
  8 }a[maxn];
  9 void pushup(int &o){
 10     a[o].siz=a[a[o].lc].siz+a[a[o].rc].siz+a[o].val;
 11     return;
 12 }
 13 void lturn(int &o){
 14     int t=a[o].rc;
 15     a[o].rc=a[t].lc;
 16     a[t].lc=o;
 17     a[t].siz=a[o].siz;
 18     pushup(o);
 19     o=t;
 20     return;
 21 }
 22 void rturn(int &o){
 23     int t=a[o].lc;
 24     a[o].lc=a[t].rc;
 25     a[t].rc=o;
 26     a[t].siz=a[o].siz;
 27     pushup(o);
 28     o=t;
 29     return;
 30 }
 31 void insert(int &o,int t){
 32     if(!o){
 33         o=++cnt;
 34         a[o]=(treap){0,0,t,rand(),1,1};//rand()隨機一個優先度
 35         return;
 36     }
 37     a[o].siz++;
 38     if(t==a[o].key)a[o].val++;
 39     else if(t<a[o].key){
 40         insert(a[o].lc,t);
 41         if(a[a[o].lc].pri>a[o].pri)rturn(o);
 42     }
 43     else{
 44         insert(a[o].rc,t);
 45         if(a[a[o].rc].pri>a[o].pri)lturn(o);//
 46     }
 47     return;
 48 }
 49 void del(int &o,int k){
 50     if(!o)return;
 51     if(k==a[o].key){
 52         if(a[o].val>1){
 53             a[o].val--;
 54             a[o].siz--;
 55         }
 56         else if(!(a[o].lc*a[o].rc)){//如果左右只有一個兒子
 57             o=a[o].lc+a[o].rc;
 58         }
 59         else if(a[a[o].lc].pri<a[a[o].rc].pri){
 60             lturn(o);
 61             del(o,k);
 62         }
 63         else{
 64             rturn(o);
 65             del(o,k);
 66         }
 67     }
 68     else if(k<a[o].key)
 69     {
 70         --a[o].siz;
 71         del(a[o].lc,k);
 72     }
 73     else
 74     {
 75         --a[o].siz;
 76         del(a[o].rc,k);
 77     }
 78     return;
 79 }
 80 int query_rank(int o,int k){
 81     if(!o)return 0;
 82     if(k<a[o].key)return query_rank(a[o].lc,k);
 83     if(k==a[o].key)return a[a[o].lc].siz+1;
 84     return a[a[o].lc].siz+a[o].val+query_rank(a[o].rc,k);
 85 }
 86 int query_num(int o,int k){
 87     if(!o)return 0;
 88     if(k<=a[a[o].lc].siz)return query_num(a[o].lc,k);
 89     if(k<=a[a[o].lc].siz+a[o].val)return a[o].key;
 90     return query_num(a[o].rc,k-a[a[o].lc].siz-a[o].val);
 91 }
 92 void query_pre(int o,int k){
 93     if(!o)return;
 94     if(k<=a[o].key)query_pre(a[o].lc,k);
 95     else{
 96         ret=a[o].key;
 97         query_pre(a[o].rc,k);
 98     }
 99     return;
100 }
101 void query_pos(int o,int k){
102     if(!o)return;
103     if(k>=a[o].key)query_pos(a[o].rc,k);
104     else{
105         ret=a[o].key;
106         query_pos(a[o].lc,k);
107     }
108     return;
109 }
110 int main(){
111     scanf("%d",&n);
112     srand(n);
113     for(int i=1;i<=n;i++){
114         scanf("%d%d",&t1,&t2);
115         if(t1==1)insert(root,t2);
116         else if(t1==2)del(root,t2);
117         else if(t1==3)printf("%d\n",query_rank(root,t2));
118         else if(t1==4)printf("%d\n",query_num(root,t2));
119         else if(t1==5){
120             ret=-inf;
121             query_pre(root,t2);
122             printf("%d\n",ret);
123         }
124         else if(t1==6){
125             ret=inf;
126             query_pos(root,t2);
127             printf("%d\n",ret);
128         }
129     }
130     return 0;
131 }

?

?

?

轉載于:https://www.cnblogs.com/Requiescat/p/7545898.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287848.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Blazor University (18)使用 RenderFragments 模板化組件 —— 創建 TabControl

原文鏈接&#xff1a;https://blazor-university.com/templating-components-with-renderfragements/creating-a-tabcontrol/創建一個 TabControl 組件源代碼[1]接下來我們將創建一個 TabControl 組件。這將教您如何實現以下目標&#xff1a;將數據傳遞到 RenderFragment 以為其…

Java之GC機制

1 JVM基本結構 1&#xff09;類加載器classLoader&#xff1a;在JVM啟動時或者類運行時將需要的.class文件加載到內存中 2&#xff09;內存區域&#xff08;運行時數據區&#xff09;&#xff1a; 是在JVM運行的時候操作所分配的內存區 3&#xff09;執行引擎&#xff1a;負…

ArcGIS實驗教程——實驗十八:疊置分析(Overlay Analysis)

ArcGIS實驗視頻教程合集:《ArcGIS實驗教程從入門到精通》(附配套實驗數據) 目 錄 一、實驗描述 二、實驗內容 三、實驗目的 四、實驗數據

《零基礎看得懂的C語言入門教程 》——(一)脫離學習誤區

本節視頻連接&#xff1a; https://www.bilibili.com/video/BV1Qv411t7ae 新手C語言學習有些誤區你應該知道&#xff0c;這樣學習起來事半功倍~一、前言 距離上一次編寫C語言的教程是5年前了&#xff08;2015年&#xff09;&#xff0c;由于自己是從初一時開始學習編程&#…

一套完整的導視設計案例_色彩導視藝術:烏克蘭基輔語言學校導視設計案例

學校導視設計案例建筑師Emil Dervish為烏克蘭基輔Underhub語言學校設計了色彩繽紛的導視系統&#xff0c;該設計靈感來源于倫敦地鐵&#xff0c;他希望通過彩色線條的大膽應用來營造輕松而歡樂的氛圍。讓我們一起來看看這座由“彩虹”做導視的學校。彩虹導視設計跟著紅色導視線…

C# 創建匿名管道

下面對匿名管道執行類似的操作。通過匿名管道&#xff0c;創建兩個彼此通信的任務。為了給管道的創建發出信號&#xff0c;使用 ManualResetEventSlim 對象&#xff0c;與內存映射文件一樣。在 Program 類的 Run 方法中&#xff0c;創建兩個任務&#xff0c;調用 Reader 和 Wri…

內測投票

create table DiaoYanTiMu &#xff08;  Ids int(10) auto_increment not null primary key(),//把所需要的都寫上中間不需要符號隔開&#xff0c;設自增長列類型必須是int&#xff0c;主鍵的話必須不能為空not null&#xff0c; Title varchar(50) not null &#xff09;;/…

Android之通過Binder機制實現IPC和linux的傳統IPC的對比分析

一、 Android的Binder機制實現IPC 這里bind機制實現實現IPC模型這里不具體分析,簡單理解就是clint-server模型 涉及到4個模塊client、server、serverManager、bind底層驅動。 serverManager的作用是將字符形式的Binder(Server創建了Binder實體)名字轉化成Client中對該Bin…

Mysql 查詢統計練習

2019獨角獸企業重金招聘Python工程師標準>>> 1、建表 customers 顧客表 products 產品表 orders 訂單表 -- 顧客表 CREATE TABLE customers (c_id INT NOT NULL AUTO_INCREMENT,lastname VARCHAR(255),firstname VARCHAR(255),address VARCHAR(255),birthday DATETI…

【經典回放】多種語言系列數據結構算法:堆排序

目錄 一、堆排序算法分析 二、C#語言實現堆排序 三、C語言實現堆排序 一、堆排序算法分析

C++11模版元編程的應用

1.概述 關于C11模板元的基本用法和常用技巧&#xff0c;我在程序員2015年2月B《C11模版元編程》一文&#xff08;后稱前文&#xff09;中已經做了詳細地介紹&#xff0c;那么C11模版元編程用來解決什么實際問題呢&#xff0c;在實際工程中又該如何應用呢&#xff1f;本文將側重…

《零基礎看得懂的C語言入門教程 》——(二)C語言沒那么難簡單開發帶你了解流程

一、學習目標 了解DevC集成開發環境了解集成開發環境了解HelloWorld程序了解HelloWorld程序的編寫方法 目錄 C語言真的很難嗎&#xff1f;那是你沒看這張圖&#xff0c;化整為零輕松學習C語言。 第一篇&#xff1a;&#xff08;一&#xff09;脫離學習誤區 第二篇&#xff1…

11選5下期算法_本周六周日【高二直播】輔導網課預告:通用技術電控二三極管、多用電表測量、數字邏輯電路、解析枚舉遞歸算法,2022浙江選考技術...

01第19-21講 2020年11月28日29日開課目錄鯨學名師考點精講系統提高高二共3階段精品課夯實基礎沖刺技術選考97-100分&#xff01;11月28日【高二|提高|直播】高二精品直播課講授&#xff1a;浙江選考技術科目第19講 高二綜合提高鯨學名師講授高中通用技術&#xff1a;第19講 電控…

十分鐘完成Bash 腳本進階!列舉Bash經典用法及其案例

前言&#xff1a;在linux中&#xff0c;Bash腳本是很基礎的知識&#xff0c;大家可能一聽腳本感覺很高大上&#xff0c;像小編當初剛開始學一樣&#xff0c;感覺會寫腳本的都是大神。雖然復雜的腳本是很燒腦&#xff0c;但是&#xff0c;當我們熟練的掌握了其中的用法與技巧&am…

【經典回放】多種語言系列數據結構算法:基數排序

目錄 一、算法思路 二、C#語言實現 三、C語言實現 一、算法思路 1. 思想基礎 基數排序的思想就是先找出待排序中的最大者&#xff0c;然后按最大者申請一個足夠大的內存空間&#xff0c;并將其初始化為零&#xff0c;然后將所有待排序的數裝入其中&#xff0c;標記裝入的數…

Java之ThreadPoolExcutor和四種常見的線程池

一、ThreadPoolExcutors的作用 java提供了ThreadPoolExcutors來創建一個線程池&#xff0c;我們為什么要用線程池呢? 1.降低資源的消耗&#xff1a;通過重復利用已經創建好的線程降低線程的創建和銷毀帶來的損耗 2.提高響應速度&#xff1a;因為線程池中的線程處于等待分配任…

探索鏈路追蹤在.NET6工業物聯網項目中的應用

如果覺得有用&#xff0c;請留言學到了。已經會了的老哥&#xff0c;請留言就這&#xff1f;可能遇到的問題工業物聯網系統自上而下一般分為ERP、Mes、SCADA、WCS、邊緣網關、設備等一個生產訂單從SAP發送到設備要經過上述多個系統&#xff0c;當某個環節出現問題&#xff0c;可…

《零基礎看得懂的C語言入門教程 》——(三)輕輕松松理解第一個C語言程序

一、學習目標 了解C語言代碼的一般結構了解函數的概念了解printf函數的使用方法了解頭文件的概念了解system函數的使用方法 目錄 C語言真的很難嗎&#xff1f;那是你沒看這張圖&#xff0c;化整為零輕松學習C語言。 第一篇&#xff1a;&#xff08;一&#xff09;脫離學習誤…

hdu_1728_逃離迷宮(bfs)

題目連接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1728 題意&#xff1a;走迷宮&#xff0c;找最小的拐角 題解&#xff1a;對BFS有了新的理解&#xff0c;DFS剪枝應該也能過&#xff0c;用BFS就要以拐角作為增量來搜&#xff0c;即以當前點為坐標&#xff0c;4…

把文件放在SD卡

2019獨角獸企業重金招聘Python工程師標準>>> 在程序中訪問SDCard&#xff0c;你需要申請訪問SDCard的權限。 在AndroidManifest.xml中加入訪問SDCard的權限如下: <!-- 在SDCard中創建與刪除文件權限--> <uses-permissionandroid:name"android.permiss…