您需要寫一種資料結構,來維護乙個有序數列,其中需要提供以下操作:應xgy的邀來碼樹套樹了...今天或許能碼完這一篇吧...還在發燒,動態區間第k大(權值線段樹套線段樹or樹狀陣列套主席樹)估計碼不完了1.查詢k在區間內的排名
2.查詢區間內排名為k的值
3.修改某一位值上的數值
4.查詢k在區間內的前驅(前驅定義為小於x,且最大的數)
5.查詢k在區間內的後繼(後繼定義為大於x,且最小的數)
所以正好分成幾天來寫,寫的細一點
這種題一般很明顯...就是又有平衡樹性質又有線段樹性質應該就是線段樹套平衡樹了吧
顧名思義,線段樹套平衡樹,就是對於線段樹的每乙個點開乙個平衡樹,利用平衡樹的靈活性和線段樹對區間處理的強大來解決問題
簡單的來說,原來線段樹每個點是乙個區間,你用平衡樹維護每個區間,最後的得到的就是線段樹套平衡樹
怎麼樣,理論非常簡單吧 然而寫起來難的一匹我會說?
來看一下這道題
opt1:線段樹常規查詢區間,每一次統計小於k的點的個數再相加。
opt2:這個是最麻煩也是最精妙的一問,解決方法是二分答案,每二分到乙個答案查詢一下這個答案在這個區間內的排名,如果排名等於k+1的話返回它的pre即可。注意這裡二分滿足條件之後不用查詢pre,答案直接為left-1,可以證明left-1一定在序列中。
opt3:相當於線段樹的點修改,在平衡樹中刪除再插入即可。
opt4:線段樹常規查詢區間,每一次找區間內比k小的最大的數,然後取max
opt5:類似於opt4,每一次找區間內比k大的最小的數,然後取min
大概就是這樣了吧- -#
懶得寫sbt,拿splay卡時限過的
大家寫sbt或者treap都是極好的,千萬不要學我
#include#includeview code#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
) }}
線段樹套平衡樹很簡單(思想層面)但它是我們學習樹套樹的基礎,建議仔細學習乙個,然後做以下例題。
這個東西練熟了,我們就可以更好的了解其他形式的樹套樹,我們還可以更好的形成"樹套樹"的思想
這個思想有助於我們寫出很多資料結構毒瘤題的正解/暴力
例題: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...