【老鼠看不懂的數據結構】FHQTreap 初識

来源:https://www.cnblogs.com/o2mouse/p/18206986
-Advertisement-
Play Games

title: Django與前端框架協作開發實戰:高效構建現代Web應用 date: 2024/5/22 20:07:47 updated: 2024/5/22 20:07:47 categories: 後端開發 tags: DjangoREST 前端框架 SSR渲染 SPA路由 SEO優化 組件庫 ...


Treap 弱平衡的隨機性很強的老鼠看不懂的平衡樹

Q:為什麼叫 Treap?
A:看看二叉搜索樹(BST)和堆(Heap),組合起來就是 Treap

其中,二叉搜索樹的性質是:
左子節點的值 (val) 比父節點小
右子節點的值 (val) 比父節點大

如果這些節點的值都一樣,這棵樹就會退化成一顆(?)鏈。

對, 我知道你在想什麼——並查集。
雖然都會被傻老鼠亂搞退化成鏈,但優化方式大有不同。

優化 - Priority - 玄學抽卡

笨蛋老鼠可能還有疑惑,為什麼鏈是naive的而樹是超棒的呢?
從OIwiki偷兩張圖來解釋:
看,這是一顆正常的樹,基本上可以看作滿二叉樹,一次查詢只需要 \(O(\log_2{n})\)的時間複雜度
正常的樹
這是一顆(?)被老鼠亂搞以後形成的鏈,一次查詢的時間複雜度劣化到了 \(O(n)\)
鏈
那麼,既然屑老鼠已經說了這棵樹有堆的性質,所以就要給每一個結點上一個隨機的優先順序\(Priority\)
讓它同時成為一個堆,在雙重特征下保持完全二叉樹的形狀

PS:傻老鼠腦子糊塗了,首先樹得滿足BST的性質,然後空下來時維護Heap的性質

大功告成,現在該知道節點裡面應該放什麼了。

node節點(為什麼不用類封裝?因為老鼠不會)
struct node{
	node *child[2];
	int val,ranf,cnt,siz;
	node(int __val) : val(__val), cnt(1), siz(1){
		child[0] = child[1] = nullptr;//左右兒子初始化 
		ranf = rand();//玄學抽卡 
	} 
	node(node *__node){
		val = __node->val, ranf = __node->ranf, cnt = __node->cnt, siz = __node->siz;
	}
	void ud_siz(){
		siz = cnt;
		if(child[0] != nullptr)siz += child[0]->siz;
		if(child[1] != nullptr)siz += child[1]->siz; 
	}
};

Treap的重要操作 Split & Merge

分裂過程接受兩個參數:根指針 \(\textit{cur}\)、關鍵值 \(\textit{key}\)。結果為將根指針指向的 treap 分裂為兩個 treap,第一個 treap 所有結點的值\(\textit{val}\)小於等於 \(\textit{key}\),第二個 treap 所有結點的值大於 \(\textit{key}\)
該過程首先判斷 \(\textit{key}\) 是否小於 \(\textit{cur}\) 的值,若小於,則說明 \(\textit{cur}\) 及其右子樹全部大於 \(\textit{key}\),屬於第二個 treap。當然,也可能有一部分的左子樹的值大於 \(\textit{key}\),所以還需要繼續向左子樹遞歸地分裂。對於大於 \(\textit{key}\) 的那部分左子樹,我們把它作為 \(\textit{cur}\) 的左子樹,這樣,整個 \(\textit{cur}\) 上的節點都是大於 \(\textit{key}\) 的。
相應的,如果 \(\textit{key}\) 大於等於 \(\textit{cur}\) 的值,說明 \(\textit{cur}\) 的整個左子樹以及其自身都小於 \(\textit{key}\),屬於分裂後的第一個 treap。並且,\(\textit{cur}\) 的部分右子樹也可能有部分小於 \(\textit{key}\),因此我們需要繼續遞歸地分裂右子樹。把小於 \(\textit{key}\) 的那部分作為 \(\textit{cur}\) 的右子樹,這樣,整個 \(\textit{cur}\) 上的節點都小於 \(\textit{key}\)
下圖展示了 \(\textit{cur}\) 的值小於等於 \(\textit{key}\) 時按值分裂的情況. ——OIWIKI

老鼠才不會解釋,因為老鼠沒腦子。

Split
pair<node *, node *> split(node *rt,int key){
	if(rt == nullptr)return {nullptr, nullptr};
	if(rt->val <= key){
	auto temp = split(rt->child[1],key);
		rt->child[1] = temp.first;
		rt->ud_siz();
		return {rt,temp.second};
	}
	else{
		auto temp = split(rt->child[0],key);
		rt->child[0] = temp.second;
		rt->ud_siz();
		return {temp.first,rt};
	}
	}

合併過程接受兩個參數:左 treap 的根指針 \(\textit{u}\)、右 treap 的根指針 \(\textit{v}\)。必須滿足 \(\textit{u}\) 中所有結點的值小於等於 \(\textit{v}\) 中所有結點的值。一般來說,我們合併的兩個 treap 都是原來從一個 treap 中分裂出去的,所以不難滿足 \(\textit{u}\) 中所有節點的值都小於 \(\textit{v}\)
在旋轉 treap 中,我們藉助旋轉操作來維護 \(\textit{priority}\) 符合堆的性質,同時旋轉時還不能改變樹的性質。在無旋 treap 中,我們用合併達到相同的效果。
因為兩個 treap 已經有序,所以我們在合併的時候只需要考慮把哪個樹「放在上面」,把哪個「放在下麵」,也就是是需要判斷將哪個一個樹作為子樹。顯然,根據堆的性質,我們需要把 \(\textit{priority}\) 小的放在上面(這裡採用小根堆)。
同時,我們還需要滿足搜索樹的性質,所以若 \(\textit{u}\) 的根結點的 \(\textit{priority}\) 小於 \(\textit{v}\) 的,那麼 \(\textit{u}\) 即為新根結點,並且 \(\textit{v}\) 因為值比 \(\textit{u}\) 更大,應與 \(\textit{u}\) 的右子樹合併;反之,則 \(\textit{v}\) 作為新根結點,然後因為 u 的值比 \(\textit{v}\) 小,與 v 的左子樹合併。——OIWIKI
老鼠懶,自己看。

Merge
node *merge(node *u,node *v){
		if(u == nullptr && v == nullptr)return nullptr;
		if(u != nullptr && v == nullptr)return u;
		if(u == nullptr && v != nullptr)return v;
		if(u->ranf < v->ranf){
			u->child[1] = merge(u->child[1],v);
			u->ud_siz();
			return u;
		}
		else{
			v->child[0] = merge(u, v->child[0]);
			v->ud_siz();
			return v;
		}
	}

不好用,才不用——⑨老鼠

作為笨蛋老鼠,能看懂這個東西怎麼用才奇怪吧,只能分裂和合併的數據結構,鬼才用嘞!
笨蛋老鼠!這個東西可以整很多活的

查詢小於等於val的數的個數:考察根節點的值和val,如果val小於根節點,遞歸進左子樹,否則遞歸進右子樹。
插入val:先查詢Rank(val),然後按照rank把整個TreapSplit成兩個,把val做成一個新節點,Merge到裡面。
刪除val:先查詢Rank(val),然後按照rank把整個TreapSplit成三個,刪除需要的點,最後Merge剩下兩個。
查詢第K個值:把整個TreapSplit成三個,輸出需要的值,最後合併起來。

好啊,你的區間呢?

誇下的海口終究會被打qwq。
發現了沒,這些個操作全是區間的,想想你的線段樹怎麼區間修改優化的?
\(LazyTag\)救我狗命對吧!
所以,直接打標記建線段樹到處亂搞,怎麼在樹鏈剖分上整的活大多數都能整!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基於rake的爬取代碼 require 'nokogiri' require 'json' require 'open-uri' namespace :spider_sbi_code_info do task table_data: :environment do options = Seleniu ...
  • 正文 中午睡得真的好香,一點都不想起床上班。我要鬧了!為什麼世界上會有上班這麼邪惡的事情。 今天開了一個一般戶。剛開始資料散成一堆,得有二十張。各種找。最後還是出了點岔子,讓客戶沒簽字就跑了。算了,無所謂了。 上午綜合各家 AI 和已有的宣傳稿,寫了一篇稿子發出去。能不能被選中投上那就不是我的事了。 ...
  • 在做商城時生成隨機一個頭像,找了一下發現用首個字元直接生成的類也不錯,和用第三方外鏈的話還是有不同的,第三方雖然圖片比較多,但是會有超時問題,所以用首字母生成方式本地搞,代碼如下: 點擊查看代碼 1、方法調用測試 letter_avatar("壹零柒") 2、生成圖片方法 function lett ...
  • Qt具有跨平臺的特性,即Qt數據結構與演算法庫本身跨平臺和編譯腳本(.pro)跨平臺。在同時具有Windows下和Linux開發的需求時,最好的建議是使用QtCreator來開發,雖然也可以使用其他的IDE配合CMake等方式,但使用QtCreator更加方便,並且操作環境完全一致。QtCreator ...
  • 使用Spring Boot開發API的時候,讀取請求參數是服務端編碼中最基本的一項操作,Spring Boot中也提供了多種機制來滿足不同的API設計要求。 接下來,就通過本文,為大家總結6種常用的請求參數讀取方式。如果你發現自己知道的不到6種,那麼趕緊來查漏補缺一下。如果你知道的不止6種,那麼告訴 ...
  • 亮數據,適合大模型數據準備的可視化高效率數據採集工具。 一、大模型訓練需要數據 大模型數據處理的流程,分為數據採集、數據清洗、數據評估和指令數據標註四個主要階段,而這些階段中最重要的就是數據採集階段,需要海量的數據才能讓大模型涌現智能。 訪問點擊: 亮數據加速數據採集。 數據採集 涉及多種數據源,包 ...
  • 相關參考 https://leejjon.medium.com/how-to-allow-cross-origin-requests-in-a-jax-rs-microservice-d2a6aa2df484 https://stackoverflow.com/questions/28065963/ ...
  • 配置 NGINX 和 NGINX Plus 作為 Web 伺服器 設置虛擬伺服器 在 NGINX Plus 配置文件中,必須包含至少一個 server 指令來定義一個虛擬伺服器。 當 NGINX Plus 處理請求時,首先選擇將服務於該請求的虛擬伺服器。 http { server { # 伺服器配 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...