題目鏈結
靜態查詢區間第k小問題。
我們先要知道,權值線段樹可以維護整體區間的桶,查詢整體區間第k小。
雖然這題是查詢子區間[l,r]的第k小,但我們可以轉化成整體區間第k小問題:
我們對每個字首都建一棵權值線段樹,用於維護出現個數。
則[1,r]區間對應的線段樹減去[1,l-1]對應的線段樹後,得到的那棵線段樹就是以[l,r]為整體區間的權值線段樹。
那麼[l,r]區間內的第k小值就等於 :[1,r]區間對應的線段樹減去[1,l-1]對應的線段樹後,得到的那棵線段樹的整體區間第k小。(這裡是線段樹合併的思想,可以證明這兩顆線段樹是具有可加性的)
(兩棵線段樹相減指對應的節點的值相減)
但是如果老老實實對每個字首都建樹的話一共有2e5棵樹,肯定不行。
而且我們注意到第i棵線段樹和第i-1棵線段樹相比其實就是單點修改,所以這時候主席樹就派上用場了。
我們先建一棵空樹,版本為0,
然後依次插入n個點,第i次插入得到的線段樹版本為i 。
建樹方法有兩種,一種是把資料離散化後建樹,
一種是動態開點建可持久化權值線段樹。(名字瞎編的,大概就是這兩種線段樹的交集?)
總結一下,這題本質上就是利用了字首建樹的線段樹可加性建主席樹,把每次詢問的[l,r]區間轉化成了一棵權值線段樹的根節點區間,於是問題就成了在相減得到的那顆權值線段樹裡面,求整體區間第k小問題。
實現過程就看**吧。
//離散化建樹
#include
using
namespace std;
#define ll long long
const
int maxn =
2e5+7;
const
int mod =
1e9+7;
const ll inf =
34359738370
;int n,m;
int a[maxn]
,h[maxn]
,size;
//h為離散化後的陣列 size為離散化去重後的個數 也即是線段樹建樹區間長度[1,size]
int tree[maxn<<5]
,lc[maxn<<5]
,rc[maxn<<5]
,cnt=0;
//對離散化後的陣列建樹後, [l,r]表示離散化陣列h[l....r]中每個數在原先陣列出現次數之和
int root[maxn]
;//每個版本的根序號 第i棵樹就是對第i個字首建的樹 根序號為root[i]
//給定序列 q次查詢 [l,r]區間的第k小
//對每個字首序列建線段樹 [l,r]區間第k小就相當於[1,r]對應的線段樹減去[1,l-1]對應的線段樹之後得到的線段樹中的第k小
//線段樹1-線段樹2 指 對應每個節點的值相減
void
build
(int
&rt,
int l,
int r)
int mid=
(l+r)
>>1;
build
(lc[rt]
,l,mid)
;build
(rc[rt]
,mid+
1,r);}
void
updata
(int
&rt,
int last,
int l,
int r,
int pos)
//last線段樹版本上的單點修改
intkth
(int ltree,
int rtree,
int l,
int r,
int k)
//ltree對應區間是[1,l-1] rtree對應區間是[1,r]
//查詢的本質就是在兩棵線段樹相減得到的線段樹上查詢整體區間第k小
intmain()
//離散化步驟 先排序後去重
sort
(h+1
,h+n+1)
; size=
unique
(h+1
,h+n+1)
-h-1
;//返回的是去重後末尾的下一位 所以要-1
build
(root[0]
,1,size)
;//第0版本的線段樹是空樹
for(
int i=
1;i<=n;i++
)while
(m--
)return0;
}
//動態開點可持久化權值線段樹
#include
using
namespace std;
#define ll long long
const
int maxn =
2e5+7;
const ll inf =
34359738370
;const
int inf =
1e9+5;
int a[maxn]
;int tree[maxn*
105]
,lc[maxn*
105]
,rc[maxn*
105]
,cnt=
0,root[maxn]
;int n,m;
inline
void
updata
(int
&rt,
int last,
int l,
int r,
int pos)
intquery
(int rt1,
int rt2,
int l,
int r,
int k)
intmain()
while
(m--
)return0;
}
P3834 模板 可持久化線段樹 2(主席樹)
luogu p3834 維護乙個陣列 1 n 可以在任意區間查詢第 k 小值 m 次 1 leq n leq 2 10 5 1 leq n leq 2 10 5 10 9 leq a i leq 10 9 統計區間內各數出現次數,從小到大統計,直到小於等於當前數的數字個數剛好大於等於 k 為了提高效...
P3834 模板 可持久化線段樹 1(主席樹)
主席樹 菜雞看了乙個晚上的時間才懂。感覺網上的部落格大都大亂。我也是找到了幾遍好一點的看了一下。參考部落格 參考部落格 首先,會主席樹的前提是會線段樹。還有,我們一般在用線段樹的時候,下標位置大都是採用了i 2 和i 2 1來作為i號的左右孩子。但是,在主席樹中,我們不可以把這種思想帶過來。因為主席...
P3834 模板 可持久化線段樹 1(主席樹)
這是個非常經典的主席樹入門題 靜態區間第k小 資料已經過加強,請使用主席樹。同時請注意常數優化 如題,給定n個整數構成的序列,將對於指定的閉區間查詢其區間內的第k小值。第一行包含兩個正整數n m,分別表示序列的長度和查詢的個數。第二行包含n個整數,表示這個序列各項的數字。接下來m行每行包含三個整數l...