【知識總結】線段樹合並及其復雜度證明


應該算是比較基礎的知識了吧 …… 隨便寫寫,主要內容是證明。

例題(現編的):有一棵 \(m\) 個點的有根樹,每個點上有若干個數,\(m\) 個點上共有 \(n\) 個數,數的規模是 \(N\) 。每次詢問給定 \(u,l,r\) ,求 \(u\) 的子樹中有多少個數在 \([l,r]\) 中。

做法是每個點開一棵線段樹,插入這個結點上的數。如果能把一個結點的線段樹的信息在合理的時間內全部插入(或者說「合並」)到它父親的線段樹中,就可以由下往上做一遍樹上遞推,這樣每個結點的線段樹都存儲的是整棵子樹的信息了。

先放代碼吧:

int merge(const int x, const int y)
{
	if (!x || !y)
		return x + y;
	int a = ++cnt;
	tree[a].sum = tree[x].sum + tree[y].sum;
	tree[a].lt = merge(tree[x].lt, tree[y].lt);
	tree[a].rt = merge(tree[x].rt, tree[y].rt);
	return a;
}

這個代碼還是相當好理解的,無需贅述。下面來證明一下復雜度。(我想了一中午終於想出一個超簡潔的證明 —— 本來以為會很復雜的)

從代碼中可以看出合並兩棵樹的復雜度約等於這兩棵樹 重合 的結點數。也就是說,每次合並的復雜度不會超過較小的那棵的點數。既然如此,總復雜度就不會超過總點數,也就是 \(O(n\log N)\) 。而訪問到一個結點才會新開一個結點,所以空間復雜度也是 \(O(n\log N)\) 。實際操作中可能空間有兩倍的常數。

哇怎么這么短就寫完了 ……


免責聲明!

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



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