靜態主席樹

2022-05-23 03:09:19 字數 1352 閱讀 4269

***主席樹:對於序列的每乙個字首建一棵以序列裡的值為下標的線段樹(所以要先離散化),記錄該字首序列裡出現的值的次數;記離散後的標記為1~n; (下面值直接用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*(n<<2)肯定會mle,我們發現對於字首[1,i]和字首[1,i+1]的線段樹,如果b[i+1]<=mid (b[i+1]表示a[i+1]離散後的標記)那麼線段樹i和線段樹i+1的左邊是完全相同的,根本不需要再建,只需要用指標指一下就好;那麼對於一棵新的線段樹其實我們最多要建的節點數為log(n);nlog(n)的節點數還是可以忍受的;

1 #include 2 #include 3 #include 4 #include 5 #include 6

using

namespace

std;

7const

int maxn = 10000 + 10;8

const

int maxnn = 100 *maxn;

9int

n, q, ms, tot;

10int

root[maxn], a[maxn], ls[maxnn], rs[maxnn], s[maxnn];

11int

num[maxn], hash[maxn];

12int find(int

x)19

return

l;20}21

void build(int x, int& y, int l, int r, int

v)30

int query(int x, int y, int l, int r, int

k)36

void read(int &x)

39while(isdigit(ch)) x = 10 * x + ch - '

0', ch =getchar();

40 x *= sig; return;41

}42void

init()

50void

work()

56return;57

}58void

print()

62int

main()

靜態主席樹

首先主席樹解決什麼樣的問題?最經典的問題就是 區間第k小問題 也就是指定乙個區間,要求求出這個區間中第k小的數字 在搞懂什麼是主席樹之前,我們要先對權值線段樹有一定的了解,下面我們就先說一下權值線段樹,然後詳細說一下主席樹以及主席樹程式的實現.權值線段樹 每個葉子節點的數值表示的是 陣列中含有這個數...

深度剖析主席樹(靜態)

主席樹 chairman tree 據說是被chairman傳開的 它是一種專門用來實現求區間第k大這類操作的資料結構 q 這不是分塊輕鬆解決的事嗎?a 是的,但是分塊時間為 q 這是不是很難,複雜度極高?a nonono,複雜度一點都不高,前置知識只有動態開點線段樹 q 那我不會怎麼辦?a 右 行...

主席樹 靜態 的輕鬆入門

n i 1 85 kj 0i2 i 1n 58 j 0ki2 emmm 最近入門了主席樹,感覺其實不是很難,主要理解了就很簡單了 畢竟 這麼短 給出乙個數列,求區間 l r 之間的第 k 大值利用數列中 n 個資料建立 n 棵樹,其中第 i 棵樹維護 1 i 這個字首內的資料資訊 第 i 棵樹中的每...