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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

图解splay / splay模板 / p3369

發布時間:2023/12/18 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图解splay / splay模板 / p3369 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、例題 p3369
  • 二、思路及代碼
    • 1.思路
    • 2.代碼


前言

splay 是 tarjan老爺子的又一發明,解決了平衡樹中的很多問題

當然,splay的內容學起來也是很復雜,于是我試著用圖的方式將這個算法展示出來

splay實現的數據結構是結構體所維護的二叉樹,每個節點保存 父節點,兒子節點,節點權值,權值出現個數,和子樹大小這幾個信息

旋轉過程主要由update(), rotate(), splay() 即 更新函數、旋轉函數、splay函數三個函數實現,其分別用來:更新旋轉后的子樹規模,左旋以及右旋,強制更新至根節點

rotate:


可對照代碼一起理解

void rotate(int x) {int y = t[x].fa;int z = t[y].fa;int k = (t[y].child[1] == x); // 用來判斷左旋還是右旋t[z].child[(t[z].child[1] == y)] = x;t[x].fa = z;t[y].child[k] = t[x].child[k ^ 1];t[t[x].child[k ^ 1]].fa = y;t[x].child[k ^ 1] = y;t[y].fa = x;update(y);update(x); }

splay:
可簡要地分為兩種情況:


對照代碼:

void splay(int x, int s) {while (t[x].fa != s) { // s 為目標根節點int y = t[x].fa, z = t[y].fa;if (z != s)(t[z].child[0] == y) ^ (t[y].child[0] == x) ? rotate(x) : rotate(y);rotate(x);}if (s == 0) root = x; }

這四個轉化并不是特別顯然,但用手畫畫還是容易理解的

然后是5個功能函數:find(), insert(), maxnext(), delete(), kth(),分別用來:查詢排名,二分插入,前繼后繼查找,刪除節點,查詢第k大,我們來一一介紹

find():
首先利用平衡樹性質遞歸查找節點,
然后進行splay變換,
排名即為左子樹大小

insert():
二分遞歸查找應插入位置,
然后開點,最后還有splay變換

maxnext():
首先對x進行find()查詢排名,
這樣x便處于根節點的位置,
其前繼和后繼節點也很明顯

delete():
刪除是一個較為復雜的操作,具體步驟如下:
首先找到這個數的前驅,把他Splay到根節點
然后找到這個數后繼,把他旋轉到前驅的底下
比前驅大的數是后繼,在右子樹
比后繼小的且比前驅大的有且僅有當前數
在后繼的左子樹上面,
因此直接把當前根節點的右兒子的左兒子刪掉就可以

kth():
查詢排名第k的數,
其實和find()也很類似,
利用平衡樹的性質,
二分查找即可

一、例題 p3369


題目鏈接:洛谷 p3369

二、思路及代碼

1.思路

很經典的平衡樹模板,直接套模板即可

借鑒了很多ybb的內容:https://www.cnblogs.com/cjyyb/p/7499020.html

2.代碼

代碼如下:

#include <iostream> using namespace std; const int maxn = 201000; struct splaytree {int fa, child[2], val, cnt, size; } t[maxn]; // 父節點,左右子節點,權值,權值出現次數,子樹大小 int root, cnt; void update(int x) {t[x].size = t[t[x].child[0]].size + t[t[x].child[1]].size + t[x].cnt; } void rotate(int x) {int y = t[x].fa;int z = t[y].fa;int k = (t[y].child[1] == x); // 用來判斷左旋還是右旋t[z].child[(t[z].child[1] == y)] = x;t[x].fa = z;t[y].child[k] = t[x].child[k ^ 1];t[t[x].child[k ^ 1]].fa = y;t[x].child[k ^ 1] = y;t[y].fa = x;update(y);update(x); } void splay(int x, int s) {while (t[x].fa != s) { // s 為目標根節點int y = t[x].fa, z = t[y].fa;if (z != s)(t[z].child[0] == y) ^ (t[y].child[0] == x) ? rotate(x) : rotate(y);rotate(x);}if (s == 0) root = x; } void find(int x) {int u = root;if (!u) return;while (t[u].child[x > t[u].val] && x != t[u].val)u = t[u].child[x > t[u].val];splay(u, 0); } void insert(int x) {int u = root, fa = 0;while (u && t[u].val != x) {fa = u;u = t[u].child[x > t[u].val];}if (u)t[u].cnt++;else {u = ++cnt;if (fa) t[fa].child[x > t[fa].val] = u;t[u].child[0] = t[u].child[1] = 0;t[cnt].fa = fa;t[cnt].val = x;t[cnt].cnt = 1;t[cnt].size = 1;}splay(u, 0); } int maxnext(int x, int f) {find(x); // 此時 x 是根節點int u = root; // f: 0 前繼, 1: 后繼if (t[u].val > x && f) return u;if (t[u].val < x && !f) return u;u = t[u].child[f];while (t[u].child[f ^ 1]) u = t[u].child[f ^ 1];return u; } void Delete(int x) {int last = maxnext(x, 0);int maxnet = maxnext(x, 1);splay(last, 0);splay(maxnet, last);int del = t[maxnet].child[0];if (t[del].cnt > 1) {t[del].cnt--;splay(del, 0);} elset[maxnet].child[0] = 0; } int kth(int x) {int u = root;while (t[u].size < x) return 0;while (1) { // 二分查找int y = t[u].child[0];if (x > t[y].size + t[u].cnt) {x -= t[y].size + t[u].cnt;u = t[u].child[1];} else if (t[y].size >= x)u = y;elsereturn t[u].val;} } int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);int n;scanf("%d", &n);insert(1e9);insert(-1e9);while (n--) {int opt, x;scanf("%d%d", &opt, &x);if (opt == 1) insert(x);if (opt == 2) Delete(x);if (opt == 3) find(x), printf("%d\n", t[t[root].child[0]].size);if (opt == 4) printf("%d\n", kth(x + 1));if (opt == 5) printf("%d\n", t[maxnext(x, 0)].val);if (opt == 6) printf("%d\n", t[maxnext(x, 1)].val);}return 0; }

總結

以上是生活随笔為你收集整理的图解splay / splay模板 / p3369的全部內容,希望文章能夠幫你解決所遇到的問題。

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