題目
區間k大值,區間極值很容易想到線段樹,如果k是個位數的話,可以考慮開k個域的線段樹= =,,,,滾~
又稱可持久化線段樹,函式式線段樹
也許是上面兩個字看的太長,同時主席兩字給人一種不明覺厲的感覺,,,so,嘿嘿嘿
關於主席樹的講解可以看這
先離散化,對每個點i,建乙個1~i的線段樹(大小是數字的個數)
記錄該字首序列裡出現的值的次數;記離散後的標記為1~n;
對於區間[x,y]的第k大的值,那麼從root[x-1],root[y]開始,
t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示區間[x,y]內值在[1,mid]的個數
先判斷t是否大於k,如果t大於k,那麼說明在區間[x,y]內存在[1,mid]的數的個數大於k,
也就是第k大的值在[1,mid]中,否則在[mid+1,r]中;
這樣我們依次同時從root[x-1],root[y]往下走
當l==r時 第k大的值就是離散後標記為l的值;
如果每棵線段都建完整的化,n^2肯定會mle,,,bang!!!
我們發現對於字首[1,i]和字首[1,i+1]的線段樹,如果b[i+1]<=mid (b[i+1]表示a[i+1]離散後的標記)
那麼線段樹i和線段樹i+1的左邊是完全相同的,根本不需要在建,直接鏈過去就好;
那麼對於一棵新的線段樹其實我們最多要建的節點數為log(n);nlog(n)的節點數,duangduangduang
存個**吧,,,,以後如果寫熟練了有空寫個去重的離散
//嘿嘿嘿
# include
# include
# include
# define n 100100
using namespace std;
int i,n,m,root[n],a[n],p[n],b[n],cnt;
struct nodet[n*30];
bool cmp(int i,int j)
int query(int
x,int
y,int l,int r,int k)
int main()
sort(p+1,p+n+1,cmp);
for (int i=1;i<=n;i++)b[p[i]]=i;
for (int i=1;i<=n;i++)
for (int i=1;i<=m;i++)
}return
0;}
hdu2665(主席樹模板題)
求區間第 k 小。參考這類題目做法挺多的,例如 劃分樹。這裡使用主席樹再寫一發,不得不說主席樹相比而言要好寫的多,比起普通線段樹,主席樹就是復用了線段樹共有的資訊。可持久化資料結構講究的就是復用共有的資訊,可持久化 trie 的思想也是差不多的。includeusing namespace std ...
hdu2665 主席樹(可持久化線段樹)
題意 給定乙個陣列,每次查詢第l到r區間的第k大值 經過這題總算對可持久化線段樹有了些了解,我們開始先建一顆空樹,然後對於每次修改我們只會修改logn個點,我們可以新建logn個來避免每次都新建一顆線段樹導致的爆空間,對於這題來說我們線段樹中維護的是這個區間的點的個數,插入的時候按權值大小插入,對於...
hdu 2665 劃分樹裸題
昨天還覺得劃分樹很難,看了一眼別人的 覺得好長然後覺得很沒法下手!今天早上起床還是很耐心的研讀了大牛的 哈哈,原來也不過如此嗎!線段樹和歸併排序的結合,建議大家以後遇到不會的題一定要有耐心,不然就真的學不會了 include include include include include inclu...