***主席樹:對於序列的每乙個字首建一棵以序列裡的值為下標的線段樹(所以要先離散化),記錄該字首序列裡出現的值的次數;記離散後的標記為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 6using
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 棵樹中的每...