1. 程式人生 > >【學習筆記】兩種非旋轉平衡樹在OI中的應用

【學習筆記】兩種非旋轉平衡樹在OI中的應用

【學習筆記】兩種非旋轉平衡樹在OI中的應用

前言

N O I P NOIP 掛完之後打算把資料結構啃完(不包括 L C

C , E T T , A V L , z
y f LCC,ETT,AVL,zyf 等神仙資料結構),於是就開始學習非旋轉的平衡樹了。然後發現自己被旋轉平衡樹坑了好久。。非旋轉的程式碼各種吊打旋轉平衡樹。。。。廢話不多說,今天主要討論的兩種非旋轉平衡樹分別是fhqTreap和替罪羊樹。

fhqTreap

非旋轉 T

r e a p Treap ,範浩強 T r e a p Treap
眾所周知, T r e a p Treap 相當於是 H e a p + B s t Heap+Bst
T r e a p Treap 的複雜度保證基於期望意義下樹的深度不超過 O ( l o g n ) O(logn) ,而Treap採用旋轉是為了滿足堆的性質。
也就是說, T r e a p Treap 的旋轉操作和複雜度並不直接掛鉤,我們拋棄以前的旋轉做法,考慮如何插入一個節點 n w nw
一種神奇的思路是,把一棵樹劈開,分成兩棵樹 l e f t , r i g h t left,right ,這兩棵樹中 v l e f t v n w < v r i g h t v_{left}\le v_{nw}<v_{right} 。把一個節點看成一棵樹,把這三棵樹合併起來。
這就是FHQ著名的兩個操作 S p l i t Split M e r g e Merge

Split

假設當前節點為 p p ,插入節點的權值是 v v ,分兩種情況。

  • v [ p ] v a l v[p]\le val ,此時當前節點以及整個左子樹都要放 l e f t left 中,之後如果再有節點放入左子樹,一定在當前節點的右邊。
  • v [ p ] > v a l v[p]> val ,此時當前節點以及整個右子樹都要放 r i g h t right 中,之後如果再有節點放入右子樹,一定在當前節點的左邊。

基於這個思路,採用引用的方式可以得到如下程式碼。

void Split(int u, int &a, int &b, int x) {
    if(!u) return void(a = b = 0);
    if(val[u] <= x)
        a = u, Split(rs[u], rs[a], b, x);
    else 
        b = u, Split(ls[u], a, ls[b], x);
    Up(u);
}

核心操作1結束了。

Merge

類似左偏樹的合併,不過採用啟發式合併,因為 T r e a p Treap 是一個堆,而 S p l i t Split 的過程保證了 M e r g e Merge 的順序,所以合併的時候比較一下鍵值大小即可。

int Merge(int u, int v) {
    if(!u || !v) return u | v;
    if(key[u] < key[v]) return rs[u] = Merge(rs[u], v), Up(u), u;
    return ls[v] = Merge(u, ls[v]), Up(v), v;
}

剩下的

插入的時候劈成兩棵樹合併即可。

void Ins(int x) {
    int a = 0, b = 0; Get(x);
    Split(rt, a, b, x);
    a = Merge(a, nw);
    rt = Merge(a, b);
}

刪除的時候劈成三棵樹刪除即可。

void Del(int x) {
    int a = 0, b = 0, c = 0;
    Split(rt, a, b, x);
    Split(a, a, c, x - 1);
    st[++tp] = c; 
    c = Merge(ls[c], rs[c]);
    a = Merge(a, c);
    rt = Merge(a, b);
}

查詢第 k k 大就是在平衡樹上二分。

int Kth(int p, int k) {
    for(;p;) {
    	if(sz[ls[p]] + 1 == k) return val[p];
    	sz[ls[p]] < k ? k -= sz[ls[p]] + 1, p = rs[p] : p = ls[p];
    }
}

查詢排名,前驅和後繼就是劈開之後找第 1 1 大或者第 n n

void Rk(int x)  {
    int a = 0, b = 0;
    Split(rt, a, b, x - 1);
    printf("%d\n", sz[a] + 1);
    rt = Merge(a, b);
}
void Pre(int x) {
    int a = 0, b = 0;
    Split(rt, a, b, x - 1);
    printf("%d\n", Kth(a, sz[a]));
    rt = Merge(a, b);
}
void Nxt(int x) {
    int a = 0, b = 0;
    Split(rt, a, b, x);
    printf("%d\n", Kth(b, 1));
    rt = Merge(a, b);
}

都是平衡樹的正常操作,非旋轉 T r e a p Treap 直觀容易理解,掌握了 M e r g e Merge S p l i t Split 之後可以快速提取出需要的樹,然後就是按照題意模擬即可。

總程式碼

來自luogu3369

#include<bits/stdc++.h>
const int N = 1e5 + 10;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int sz[N], ls[N], rs[N], val[N], key[N], st[N], tp, tot, rt = 1, nw, se = 233;
int Rand() {return se = 1LL * se * 998244353 & 0x7fffffff;}
void Get(int k) {
    nw = tp ? st[tp--] : ++tot;
    sz[nw] = 1; val[nw] = k; key[nw] = Rand();
    ls[nw] = rs[nw] = 0;
}
void Up(int u) {sz[u] = sz[ls[u]] + sz[rs[u]] + 1;}
void Split(int u, int &a, int &b, int x) {
    if(!u) return void(a = b = 0);
    if(val[u] <= x)
        a = u, Split(rs[u], rs[a], b, x);
    else 
        b = u, Split(ls[u], a, ls[b], x);
    Up(u);
}
int Merge(int u, int v) {
    if(!u || !v) return u | v;
    if(key[u] < key[v]) return rs[u] = Merge(rs[u], v), Up(u), u;
    return ls[v] = Merge(u, ls[v]), Up(v), v;
}
int Kth(int p, int k) {
    for(;p;) {
    	if(sz[ls[p]] + 1 == k) return val[p];
    	sz[ls[p]] < k ? k -= sz[ls[p]] + 1, p = rs[p] : p = ls[p];
    }
}
void Rk(int x)  {
    int a = 0, b = 0;
    Split(rt, a, b, x - 1);
    printf("%d\n", sz[a] + 1);
    rt = Merge(a, b);
}
void Pre(int x) {
    int a = 0, b = 0;
    Split(rt, a, b, x 
            
           

相關推薦

學習筆記旋轉平衡OI應用

【學習筆記】兩種非旋轉平衡樹在OI中的應用 前言 N O I

學習筆記資料庫優化之索引(聚簇索引&聚簇索引)

索引:對資料庫表中一列或多列的值進行排序的一種結構,通過索引可快速訪問資料庫表中的特定資訊,即通過索引對資料列的值進行結構化排序。 其中,索引包含聚簇索引和非聚簇索引 聚簇索引的順序就是資料的物理儲存順序 非聚簇索引的索引順序與資料物理排列順序無關 所以一個表

學習筆記關於DOM4J:使用DOM4J解析XML文檔

文本 class 中產 獲取 ber exce int() logs hone 一、概述 DOM4J是一個易用的、開源的庫,用於XML、XPath和XSLT中。采用了Java集合框架並完全支持DOM、SAX、和JAXP。 DOM4J最大的特色是使用大量的接口,主要接口都在o

學習筆記Java生成對象的5方法

目標 獲得 cti com pre lan except 我們 highlight 概述:本文介紹以下java五種創建對象的方式: 1.用new語句創建對象,這是最常用的創建對象的方式。 2.使用Class類的newInstance方法 3.運用反射手段,調用java.la

學習筆記SIFT尺度不變特征 (配合UCF-CRCV課程視頻)

rri cnblogs -o mask 畫出 blocks http ucf 產生 SIFT尺度不變特征 D. Lowe. Distinctive image features from scale-invariant key points, IJCV 2004 -Lect

學習筆記String進階:StringBuffer類(線程安全)和StringBuilder類

n) static this util double 字符串 對象 ice 單線程 一、除了使用String類存儲字符串之外,還可以使用StringBuffer類存儲字符串。而且它是比String類更高效的存儲字符串的一種引用數據類型。 優點:   對字符串進行連接操作時,

學習筆記使用SQLyog連接MySQL數據庫

comm 丟失 school turn 復合主鍵 price not email pre 一、使用SQLyog創建數據庫用來管理學生信息 1 #創建數據庫student 2 DROP DATABASE IF EXISTS Myschool; 3 CREAT

學習筆記2017年7月18日MySQL測試:模擬QQ數據庫

關系 ref sts one database 等級 weight insert phone 模擬測試: QQ數據庫管理 一、創建數據庫並添加關系和測試數據 1 ##創建QQ數據庫,完成簡單的測試 2 3 #創建數據庫 4 DROP DATABASE IF EX

學習筆記C# 構造和析構

成員 int 學習 pri [] func 釋放內存 ring 銷毀 構造方法 構造方法是一個特殊的方法,負責初始化對象 構造方法名必須和類名一致 構造方法沒有返回值,但可以有參數,能夠重載 構造方法可以不寫,系統會自動為類添加一個無參的默認構造 如果將構造方法設置為P

學習筆記C# 靜態類

實例化 namespace [] line str 過程 ole test 數據 靜態修飾符 用static修飾的成員是靜態成員 靜態成員只能由類來調用 用static修飾的類是靜態類 靜態類不能實例化,只能包含靜態成員和const常量 在內存中一共有五個區域 1

學習筆記C# 接口

apple [] oat 訪問 names 使用 foo pub 修飾 使用interface關鍵字定義接口 接口定義一組成員但不直接實現它們 實現接口 實現接口的任何類都必須實現其所有的成員方法 接口不能直接實例化 接口可以包含方法和屬性聲明,不能包含字段 接口中所有

學習筆記C# ArrayList

tde 獲取 style demo key ren mov cnblogs content 集合 集合是種容器,在程序中,使用集體管理相關對象組 集合分為非泛型集合和泛型集合 非泛型集合 使用非泛型集合需要引入命名空間System.Collections Arra

學習筆記C# 字典

鍵值對 保存 包含 ear 是否 nod 對象 命名空間 不包含 字典 Dictionary是存儲鍵和值的集合 Dictionary是無序的,鍵Key是唯一的 使用時,首先要引入泛型集合命名空間 using System.Collections.Generic;

學習筆記python爬取百度真實url

python 今天跑個腳本需要一堆測試的url,,,挨個找復制粘貼肯定不是程序員的風格,so,還是寫個腳本吧。 環境:python2.7 編輯器:sublime text 3 一、分析一下 首先非常感謝百度大佬的url分類非常整齊,都在一個

學習筆記WebDriver操作第三方控件

webdriver 第三方控件 本文是風落幾番(任健勇)老師的課程《從零學習selenium2(WebDriver)自動化測試系列視頻課程》Lesson3-4第三方控件類操作的學習筆記第三方控件的操作,不同控件的操作方法一、上傳控件1.標準控件經過包裝:在標準的上傳控件input type=file之

學習筆記盧卡斯定理

namespace style pan set thml color 怎麽辦 alt fontsize 洛谷 P3807 【模板】盧卡斯定理 題目背景 這是一道模板題。 題目描述 給定n,m,p(1\le n,m,p\le 10^51≤n,m,p≤10?5??) 求 C_{

學習筆記計算機網絡-利用TELNET進行SMTP的郵件發送

alt tle smtp 用戶 sdn 編碼 out mark watermark 在命令行輸入telnet smtp.163.com 25 然後依次輸入內容 用戶名不包括@和後面的部分,用戶名和密碼均需base64編碼 成功收到郵件: 【學習筆記】計算機網絡-利用TEL

學習筆記python 進階特性

可能 pytho red nbsp python blog 有一個 自省 blue __slots__魔法 在Python中,每個類都有實例屬性。默認情況下Python用一個字典來保存一個對象的實例屬性。這非常有用,因為它允許我們在運行時去設置任意的新屬性。 然而,對於有

學習筆記初識FreeMarker簡單使用

als 大小 宋體 屬性 list mage equal port template 楔子:    之前在和同事討論,同事說“jsp技術太古老了,有幾種頁面技術代替,比如FreeMarker、Velocity、thymeleaf,jsp快廢棄了……”雲雲。我這一聽有點心虛…

學習筆記FreeMarker 之於Servlet與Stuts2的應用

patch warnings ftl 4.0 type shm .html enter src FreeMarker應用在Servlet(0配置web.xml形式): 準備環境: tomcat7、eclipse最新版、jdk1.8、freemarker v2.3.20.ja