可持久化線段樹——Step 1 靜態區間第K大
考慮這樣一個問題:
給出一段長度為n序列
關於暴力做法,其實是很簡單的,但是會超時,在此略過。
有一種辦法,是利用字首和的思想。先將
這樣,對於序列上的某一段
如果不考慮記憶體,那麼問題已經解決了,但是對於序列上的任意一點,我們都建立了一棵線段樹,此時空間複雜度已經達到平方級別,顯然不行。
但是考慮到一個巧妙的現象,對於第
首先明確一個顯而易見的事實:無論如何,這n棵權值線段樹的結構形態都是一樣的。
對於權值線段樹上的任意一個節點,新加入一個屬於它的值進來,顯然這個節點的值要+1,然後再向下更新。但是,它就只有兩個兒子節點,這個更新的方向不是往左就是往右。
那麼這時對於第
如何確定不用更改的那些呢?很簡單,對於這條鏈上的任意一個非葉子節點,它有兒子的那一邊就不管,另一個子節點直接沿用上一棵線段樹的相應節點就行了。最後向上更新就行了。
給出參考程式碼:
#include <bits/stdc++.h>
using namespace std ;
bool Read ( int &x ) { char c = getchar() ; x = 0 ; bool f = 0 ; while ( !isdigit(c) ) { if ( c == '-' ) f = 1 ; if ( c == EOF ) return false ; c = getchar() ; } while ( isdigit(c) ) { x = 10 * x + c - '0' ; c = getchar() ; } if (f) x = -x ;return true ; }
void Print ( int x ) { int len = 0, a[50] ; if ( x == 0 ) { putchar('0') ; return ; } if ( x < 0 ) { putchar('-') ; x = -x ; } while (x) { a[++len] = x%10 ; x /= 10 ; } while (len) putchar(a[len--]+'0') ;}
const int maxn = 100010 ;
int n, m, rt[maxn], Rank[maxn], cnt ;
struct node {
int l, r, v ;
} tree[maxn<<5] ;
struct nodd {
int v, id ;
friend bool operator < ( nodd a, nodd b ) {
return a.v == b.v ? a.id < b.id : a.v < b.v ;
}
} a[maxn] ;
void insert ( int K, int& x, int l, int r ) {
tree[++cnt] = tree[x] ;
x = cnt ;
++ tree[x].v ;
int mid = l+r >> 1 ;
if ( l == r ) return ;
if ( K <= mid ) insert ( K, x[tree].l, l, mid ) ;
else insert ( K, x[tree].r, mid+1, r ) ;
}
int query ( int rt1, int rt2, int l, int r, int K ) {
if ( l == r ) return l ;
int mid = l+r >> 1 ;
int num = tree[rt2].l[tree].v - tree[rt1].l[tree].v ;
if ( K <= num ) return query ( rt1[tree].l, rt2[tree].l, l, mid, K ) ;
else return query ( rt1[tree].r, rt2[tree].r, mid+1, r, K-num ) ;
}
int main() {
int i, j, k, x, y ;
Read(n) ; Read(m) ;
for ( i = 1 ; i <= n ; i ++ ) {
Read(a[i].v) ;
a[i].id = i ;
}
sort ( a+1, a+n+1 ) ;
for ( i = 1 ; i <= n ; i ++ )
a[i].id[Rank] = i ;
for ( i = 1 ; i <= n ; i ++ ) {
rt[i] = rt[i-1] ;
insert ( Rank[i], rt[i], 1, n ) ;
}
while ( m-- ) {
Read(x) ; Read(y) ; Read(k) ;
Print( a[query( rt[x-1], rt[y], 1, n, k )].v ) ;
putchar('\n') ;
}
return 0 ;
}
是不是挺簡單的啊~
相關推薦
可持久化線段樹——Step 1 靜態區間第K大
考慮這樣一個問題: 給出一段長度為n序列{ai},對於一些詢問{L,R,K}請輸出序列上[L,R]內第K大的數。 關於暴力做法,其實是很簡單的,但是會超時,在此略過。 有一種辦法,是利用字首和的思想。先將{ai}離散到區間[1,n],然後,對於任意節點i,
HDU2665 主席樹原理解決靜態區間第K大值問題總結 有詳細圖解和程式碼解釋
鄙人不才,剛學習了一點主席樹,想自己來寫一篇關於主席樹的詳解,主要針對主席樹解決靜態(無修改)區間內第K大值的問題,可以參考HDU 2665。解決其他的問題的主席樹演算法等自己搞懂後再補上。下文如果有什麼錯誤還請指出,感激不盡! 感謝以下博文對主席樹的講解: 1.主席樹1
HDU 4348.To the moon-可持久化線段樹(帶修改線上區間更新(增減)、區間求和,延時標記不下放(空間優化))
To the moon Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 8372
[poj 2104]主席樹+靜態區間第k大
include end 區間 得到 name int 題目 tar tdi 題目鏈接:http://poj.org/problem?id=2104 主席樹入門題目,主席樹其實就是可持久化權值線段樹,rt[i]維護了前i個數中第i大(小)的數出現次數的信息,通過查詢兩棵樹的差
靜態區間第k大 樹套樹解法
i++ val pri math 1+n std -a 平衡樹 scanf 然而過不去你谷的模板 思路: 值域線段樹\([l,r]\)代表一棵值域在\([l,r]\)範圍內的點構成的一顆平衡樹 平衡樹的\(BST\)權值為點在序列中的位置 查詢區間第\(k\)大值時 左區間
靜態區間第k大(歸併樹)
POJ 2104為例 思想: 利用歸併排序的思想: 建樹過程和歸併排序類似,每個數列都是子樹序列的合併與排序。 查詢過程,如果所查詢區間完全包含在當前區間中,則直接返回當前區間內小於所求數的
HDU 2665 Kth number(主席樹靜態區間第K大)題解
可持久化 unique algorithm using 主席樹 可持久化線段樹 long spa 靜態區 題意:問你區間第k大是誰 思路:主席樹就是可持久化線段樹,他是由多個歷史版本的權值線段樹(不是普通線段樹)組成的。 具體可以看q學姐的B站視頻 代碼:
Permutation UVA - 11525(值域樹狀數組,樹狀數組區間第k大(離線),log方,log)
一次 跳過 += 數字 div ret num while printf Permutation UVA - 11525 看康托展開 題目給出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展開(將n個數的所有排列按字典序
ZOJ -2112 Dynamic Rankings 主席樹 待修改的區間第K大
OS alt \n tar txt push fopen amp get Dynamic Rankings 帶修改的區間第K大其實就是先和靜態區間第K大的操作一樣。先建立一顆主席樹, 然後再在樹狀數組的每一個節點開線段樹(其實也是主席樹,共用節點), 每次修改的時候都按照
整體二分初步——靜態區間第k大
Description 給定一個長度為n的序列,m個詢問,每個詢問的形式為:L,r,k表示在[L,r]間中的第k大元素。 Input 第1行:2個數,n,m表示序列的長度和詢問的個數 第2行:n個數,表示n個數的大小 第3-m+2行:每行3個數,L,r,k表示詢問在[L
靜態區間第K大
<a target=_blank href="http://poj.org/problem?id=2104" target="_blank"><span style="font-s
2665 Kth number (靜態區間第k大)
Give you a sequence and ask you the kth big number of a inteval. InputThe first line is the numbe
POJ 題目2985 The k-th Largest Group(線段樹單點更新求第k大值,並查集)
The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 7869 Accepted: 2534 Description Newman likes play
落谷 P3834 可持久化線段樹 1(主席樹)(區間第k小)
設區間為l,r,用r版本減去l版本求出區間第k小,一個板子 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using
【模板】可持久化線段樹 1(主席樹)
base math 一次 數據 mar 指定 das min 第k小 題目背景 這是個非常經典的主席樹入門題——靜態區間第K小 數據已經過加強,請使用主席樹。同時請註意常數優化 題目描述 如題,給定N個正整數構成的序列,將對於指定的閉區間
[Luogu] 可持久化線段樹 1(主席樹)
tdi ace oid root post space out 節點 nod https://www.luogu.org/problemnew/show/P3834 #include<cstdio> #include<iostream> #
【XSY2720】區間第k小 整體二分 可持久化線段樹
cpp markdown 區間 序列 printf line 線段 using back 題目描述 給你你個序列,每次求區間第\(k\)小的數。 本題中,如果一個數在詢問區間中出現了超過\(w\)次,那麽就把這個數視為\(n\)。 強制在線。 \(n\leq
【9018:2207】可持久化線段樹1
正整數 page sta 輸出 amp status efi oid 所有 2207: 【模板】可持久化線段樹1 時間限制: 2 Sec 內存限制: 256 MB提交: 45 解決: 14[提交][狀態][討論版] 題目描述 你需要維護1個數列的若幹版本: 對於給定的
【刷題】洛谷 P3834 【模板】可持久化線段樹 1(主席樹)
!= tchar 這樣的 信息 reg har mem hair define 題目背景 這是個非常經典的主席樹入門題——靜態區間第K小 數據已經過加強,請使用主席樹。同時請註意常數優化 題目描述 如題,給定N個正整數構成的序列,將對於指定的閉區間查詢其區間內的第K小值。
可持久化線段樹 區間第k大
getchar() AI 多少 lin urn pri 長度 != register 2018-04-04 http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1175 一個長度為N的整數序列,編號0