hdu_1166敵兵佈陣

在網上下到acm大牛總結的線段樹專輯,其代碼風格我學到了很多。

線段樹,類似區間樹,是完全二叉樹,它在各個節點保存一條線段(數組中的一段子數組),主要用於高效解決連續區間的動態查詢問題,由於二叉結構的特性,它基本能保持每個操作的複雜度爲O(lgN)!

性質:父親的區間是[a,b],用二分法的思想去分左右兒子,左兒子爲[a,(a+b)/2],右兒子爲[(a+b)/2+1,b],因此線段樹所需空間爲最大數的4倍


首先宏定義左右兒子:

#define lson l,m,rt<<1<span>	//結點爲rt,區間爲[l,m]</span>
#define rson m+1,r,rt<<1|1 <span>	//結點爲rt,區間爲[m+1,r]</span>



計算父節點的總值,總值爲左右兒子值的總和:

<span style="font-family:FangSong_GB2312;">inline void fatherSum(int rt){
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}</span>


用遞歸思想構造線段樹:

<span style="font-family:FangSong_GB2312;">void buildTree(int l,int r,int rt){
	if(l == r){
		scanf("%d",&sum[rt]);
		return;
	}
	int m = (l+r)>>1;
	buildTree(lson);
	buildTree(rson);
	fatherSum(rt);
} </span>


線段樹對應結點更新以及父節點更新以及父節點的父節點的更新...,樹根遍歷到對應結點所經過的結點的值都要更新:

<span style="font-family:FangSong_GB2312;">void update(int p,int num,int l,int r,int rt){
	if(l == r){
		sum[rt] += num;
		return;
	}
	int m = (l+r)>>1;
	if(p <= m)
		update(p,num,lson);
	else
		update(p,num,rson);
	fatherSum(rt);
}</span>


區間查詢:

<span style="font-family:FangSong_GB2312;">int query(int L,int R,int l,int r,int rt){
	if(L <= l && r <= R)
		return sum[rt];
	int m = (l+r)>>1;
	int ret = 0;
	if(L <= m) 	
		ret += query(L,R,lson);
	if(R > m)	
		ret += query(L,R,rson);
	return ret;
}</span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章