樹套樹Day1線段樹套平衡樹bzoj3196

2022-05-22 22:27:12 字數 4311 閱讀 5061

您需要寫一種資料結構,來維護乙個有序數列,其中需要提供以下操作:

1.查詢k在區間內的排名

2.查詢區間內排名為k的值

3.修改某一位值上的數值

4.查詢k在區間內的前驅(前驅定義為小於x,且最大的數)

5.查詢k在區間內的後繼(後繼定義為大於x,且最小的數)

應xgy的邀來碼樹套樹了...今天或許能碼完這一篇吧...還在發燒,動態區間第k大(權值線段樹套線段樹or樹狀陣列套主席樹)估計碼不完了

所以正好分成幾天來寫,寫的細一點

這種題一般很明顯...就是又有平衡樹性質又有線段樹性質應該就是線段樹套平衡樹了吧

顧名思義,線段樹套平衡樹,就是對於線段樹的每乙個點開乙個平衡樹,利用平衡樹的靈活性和線段樹對區間處理的強大來解決問題

簡單的來說,原來線段樹每個點是乙個區間,你用平衡樹維護每個區間,最後的得到的就是線段樹套平衡樹

怎麼樣,理論非常簡單吧    然而寫起來難的一匹我會說?

來看一下這道題

opt1:線段樹常規查詢區間,每一次統計小於k的點的個數再相加。 

opt2:這個是最麻煩也是最精妙的一問,解決方法是二分答案,每二分到乙個答案查詢一下這個答案在這個區間內的排名,如果排名等於k+1的話返回它的pre即可。注意這裡二分滿足條件之後不用查詢pre,答案直接為left-1,可以證明left-1一定在序列中。 

opt3:相當於線段樹的點修改,在平衡樹中刪除再插入即可。 

opt4:線段樹常規查詢區間,每一次找區間內比k小的最大的數,然後取max 

opt5:類似於opt4,每一次找區間內比k大的最小的數,然後取min

大概就是這樣了吧- -#

懶得寫sbt,拿splay卡時限過的

大家寫sbt或者treap都是極好的,千萬不要學我

#include#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

const

int maxn=4e6+233

;const

int inf=2147483233

; int

ans;

inta[maxn];

intn,m;

struct seg_tao_splay//

原**是分開寫的...但是太醜了

inline

void pushup(int x)

inline

void sclear(int x)

inline

void rotate(int

x)

inline

void splay(int

x)

inline

void sinsert(int i,int x)//

在splay裡加點

while("

woxihuankeduoli")

faf=now;

now=son[now][key[now]

if(!now)}}

inline

void sfind(int i,int

x)

else

if (key[now]>x) now=son[now][0

];

else

if (key[now]1

]; }

}inline

int spre(int

i)

inline

int snext(int

i)

inline

void sdel(int

i)

if (!son[now][0]&&!son[now][1

])

if (!son[now][0

])

if (!son[now][1

])

int leftm=spre(i),prert=rt[i];

splay(leftm); rt[i]=leftm;

son[rt[i]][

1]=son[prert][1

]; fa[son[prert][

1]]=rt[i];

sclear(prert);

pushup(rt[i]);

return

; }

inline

int sfindrank(int i,int

x)

else

if (key[now]>x) now=son[now][0

]; }

}inline

int sfindpre(int i,int

k)

else now=son[now][0

]; }

return

ans;

}inline

int sfindnext(int i,int

k)

else now=son[now][1

]; }

return

ans;

}//以上為splay操作 下面是線段樹操作

inline void insertseg(int id,int l,int r,int x,int

v)

inline

void askrankseg(int id,int l,int r,int lrange,int rrange,int

k)

if (lrange<=mid) askrankseg(id<<1

,l,mid,lrange,rrange,k);

if (mid+1

<=rrange) askrankseg(id<<1|1,mid+1

,r,lrange,rrange,k);

}inline

void changeseg(int id,int l,int r,int x,int

k)

inline

void askpreseg(int id,int l,int r,int lrange,int rrange,int

k)

if (lrange<=mid) askpreseg(id<<1

,l,mid,lrange,rrange,k);

if (mid+1

<=rrange) askpreseg(id<<1|1,mid+1

,r,lrange,rrange,k);

}inline

void asknextseg(int id,int l,int r,int lrange,int rrange,int

k)

if (lrange<=mid) asknextseg(id<<1

,l,mid,lrange,rrange,k);

if (mid+1

<=rrange) asknextseg(id<<1|1,mid+1

,r,lrange,rrange,k);

}}tree;

int _max=-2147483233

;int

opt,l,r,k,le,ri,md;

intmain()

for(int i=1;i<=m;i++)

if(opt==2

)

printf(

"%d\n

",le-1

); }

if(opt==3

)

if(opt==4

)

if(opt==5

) }}

view code

線段樹套平衡樹很簡單(思想層面)但它是我們學習樹套樹的基礎,建議仔細學習乙個,然後做以下例題。

這個東西練熟了,我們就可以更好的了解其他形式的樹套樹,我們還可以更好的形成"樹套樹"的思想

這個思想有助於我們寫出很多資料結構毒瘤題的正解/暴力

例題:bzoj1901  zoj2112 dynamic rankings    注:此題也叫「可持久化主席樹」所以絕對有樹狀陣列套主席樹的做法

bzoj2120  數顏色   注:正解帶修改莫隊

題解我會慢慢寫,畢竟樹套樹寫乙個也不是那麼簡單啊qaq

二逼平衡樹 樹套樹(線段樹套Splay平衡樹)

題面 bzoj3196 解析線段樹和splay兩棵樹套在一起,常數直逼inf,但最終僥倖過了 思路還是比較簡單,在原陣列維護乙個下標線段樹,再在每乙個線段樹節點,維護乙個對應區間的權值splay。簡單說一下操作 0.提取區間 1.查詢區間內k的排名 提取區間,找到區間內所有的splay,分別比k小的...

樹套樹 線段樹套set

請你寫出一種資料結構,來維護乙個長度為 n 的序列,其中需要提供以下操作 1 pos x,將 pos 位置的數修改為 x。2 l r x,查詢整數 x 在區間 l,r 內的前驅 前驅定義為小於 x,且最大的數 數列中的位置從左到右依次標號為 1 n。區間 l,r 表示從位置 l 到位置 r 之間 包...

線段樹套平衡樹 BZOJ3196

bzoj3196,tyvj1730.題目 您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x...