詳解權值線段樹


詳解權值線段樹

本篇隨筆詳細講解一下算法競賽中的一種數據結構——權值線段樹。

前置知識

在講解權值線段樹之前,我們首先要明確:權值線段樹屬於一種線段樹,它的本質仍然是線段樹。所以在學習權值線段樹之前,如果還對普通線段樹並沒有一個深刻的了解的話,請先移步這篇博客來學習簡單線段樹。

簡單線段樹知識點詳解

以及,權值線段樹的本質是線段樹維護桶。這個桶到底是什么呢?如果讀者對桶的概念和應用比較模糊的話,請移步這篇博客來學習桶的基本概念和應用:

桶的基本概念和應用

權值線段樹的概念

那么,在了解了所有的前置知識之后,理解權值線段樹便變得容易許多了。

我們知道,普通線段樹維護的信息是數列的區間信息,比如區間和、區間最大值、區間最小值等等。在維護序列的這些信息的時候,我們更關注的是這些數本身的信息,換句話說,我們要維護區間的最值或和,我們最關注的是這些數統共的信息。而權值線段樹維護一列數中數的個數

我們來看這樣一個數列:

\[1\,\,1\,\,1\,\,2\,\,3\,\,3\,\,4\,\,5\,\,5\,\,6\,\,6\,\,7 \]

一棵權值線段樹的葉子節點維護的是“有幾個1”,“有幾個2”...,他們的父親節點維護的是“有幾個1和2”。

然后我們恍然大悟:這個東西就是我們剛剛說過的“桶”。

也就是說,我們的權值線段樹就是用線段樹維護了一堆桶。

這就是權值線段樹的概念。

權值線段樹和簡單線段樹的區別

權值線段樹維護的是桶,按值域開空間,維護的是個數

簡單線段樹維護的是信息,按個數可開空間,維護的是特定信息

權值線段樹的用途

權值線段樹可以解決數列第k大/小的問題。

這里要注意!我們只能對給定數列解決整個數列的第k大/小,並不能解決數列的子區間的第k大/小。

(劇透一下,解決數列子區間的第k大/小需要主席樹(可持久化線段樹),因為蒟蒻還不會,以后會的時候可能會補講解,希望大家海涵)

一些直覺強的讀者可能已經隱約體會到權值線段樹是如何維護數列第k大/小了。沒錯,因為我們的權值線段樹維護的是一堆桶,每個節點儲存的是節點維護區間(就是值域)的數出現的次數(再次強調定義),那么,根據這個定義,整棵線段樹的根節點就表示整個值域有幾個數。對於整列數中第k大/小的值,我們從根節點開始判斷(這里按第k大為例),如果k比右兒子大,就說明第k大的數在左兒子所表示的值域中。然后,k要減去右兒子。(這是因為繼續遞歸下去的時候,正確答案,整個區間的第k大已經不再是左兒子表示區間的第k大了,很好理解)。

依次遞歸下去,到了葉子節點的時候,葉子節點就是我們要找的正確答案。

權值線段樹的相關操作及權值線段樹模板

建樹

#define lson pos<<1
#define rson pos<<1|1
void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		tree[pos]=a[l];//a[l]表示數l有多少個
		return;
	}
	build(lson,l,mid);
	build(rson,mid+1,r);
	tree[pos]=tree[lson]+tree[rson];
}

修改(插入)

void update(int pos,int l,int r,int k,int cnt)//表示數k的個數多cnt個
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		tree[pos]+=cnt;
		return;
	}
	if(k<=mid)
		update(lson,l,mid,k,cnt);
	else	
		update(rson,mid+1,r,k,cnt);
	tree[pos]=tree[lson]+tree[rson];
}

查詢

int query(int pos,int l,int r,int k)//查詢數k有多少個
{
	int mid=(l+r)>>1;
	if(l==r)
		return tree[pos];
	if(k<=mid)
		return query(lson,l,mid,k);
	else
		return query(rson,mid+1,r,k);
}

查詢第K大/小值

int kth(int pos,int l,int r,int k)//查詢第k大值是多少
{
	int mid=(l+r)>>1;
	if(l==r)
		return l;
	if(k<mid)
		return kth(rson,mid+1,r,k);
	else
		return kth(lson,l,mid,k-mid);
}

查詢k小值同理。請讀者根據自行理解再寫出查詢K小值的模板,就當作本次學習的練習吧!

權值線段樹的相關內容大約就是這樣。感謝大家的觀看和支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM