生活随笔
收集整理的這篇文章主要介紹了
线段树——入门
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
首先線段樹形象來說就是將數(shù)組看成一個線段,然后不斷的進行分割,保存在樹中的不同節(jié)點上,有點類似于b_樹的定義吧
觀察上圖,首先將整個數(shù)組的某種信息(最大值或者最小值等)保存在根節(jié)點,對應【1,8】
然后對【1,8】線段進行平分,得到【1,4】和【5,8】兩個線段,掛在樹的第二層。這樣節(jié)點2保存了數(shù)組中【1,4】的某種信息(最大值或者最小值等),節(jié)點3保存了【5,8】中的某種信息。以此類推,直到線段長度為1,即葉子節(jié)點。
所以,要找尋數(shù)組中某一區(qū)間的某些信息,就直接從書中的某個節(jié)點或者多個節(jié)點的組合就可以得到了。
? 線段樹的操作主要有 建樹,查詢,更新。其中更新包括單點更新和區(qū)間更新。
下面代碼是 OJ上 I Hate It (百度一下)的解答,可以對照著看。代碼中注釋很詳細,自己可以好好研究一下代碼。
#include <cstdio>
#include <algorithm>
using namespace std;
//線段樹 數(shù)組實現(xiàn) 單點更新
#define MAX_NODE 200005
int in[MAX_NODE];
int segtree[4*MAX_NODE+10];int build_tree(int root , int left , int right){if (left == right){segtree[root] = in[left];// printf("node = %d value = %d\n" ,root, in[left]);return -1;}if (right<left)return -1;int mid = (left+right)/2;build_tree(root*2 , left , mid);build_tree(root*2+1 , mid+1 , right);segtree[root] = max(segtree[root*2] , segtree[root*2+1]);
}int query_tree(int root , int left , int right , int start ,int end){//找出start 到 end 區(qū)間的最值if(start>right || end<left)//如果該節(jié)點記錄的區(qū)間與查詢的區(qū)間沒有交集return -1;if (left>=start && right<=end)//如果該節(jié)點記錄的區(qū)間是查詢區(qū)間的子集return segtree[root];//剩余情況就是 該節(jié)點記錄的區(qū)間大于待查詢的區(qū)間 或者 該節(jié)點記錄的區(qū)間與待查詢區(qū)間有交集// 節(jié)點記錄區(qū)間大于待查詢區(qū)間時,繼續(xù)遞歸查詢左右子樹//節(jié)點記錄的區(qū)間與待查詢區(qū)間有交集 , 左右子樹總有一個是記錄待查詢區(qū)間的子集int mid = (left+right)>>1;int part1 = query_tree(root*2 , left ,mid,start,end);//查詢左子樹int part2 = query_tree(root*2+1 , mid+1 , right ,start , end);//查詢右子樹//下面兩個判斷是針對節(jié)點記錄的區(qū)間與待查詢區(qū)間有交集但不是待查詢區(qū)間的子集。這樣肯定左右子樹中有一個包含了待查詢區(qū)間的子集if (part1 == -1)//如果左子樹不包含待查詢區(qū)間return part2;if (part2 == -1)//如果右子樹不包含待查詢區(qū)間return part1 ;//節(jié)點記錄區(qū)間大于待查詢區(qū)間時,此時左右子樹都包含了待查詢區(qū)間,所以取左右子樹返回的一個最大值最為待求區(qū)間的最大值return max(part1,part2);//
}
int update_tree(int root , int left , int right , int updatenode , int value){//updatenode是待更新的節(jié)點的區(qū)間值,value是該節(jié)點的值if (left == right){segtree[root] = value;// printf("D%d update %d\n",root,value);return -1;}int mid = (left+right)>>1;if (mid<updatenode){update_tree(root*2+1,mid+1,right,updatenode, value);}else{update_tree(root*2,left,mid,updatenode,value);}//回溯更新父節(jié)點segtree[root] = max(segtree[root*2],segtree[root*2+1]);// printf("%d update %d\n",root,segtree[root]);
}
int main (){int m,n;while (~scanf("%d%d",&n,&m)){for (int i = 0 ; i < n ; i ++)scanf("%d",&in[i]);build_tree(1,0,n-1);//root 根節(jié)點號碼必須從大于0的數(shù)開始char c;int a,b;for (int i= 0 ; i < m ; i ++){scanf("\n%c%d%d",&c,&a,&b);if (c=='Q')printf("%d\n",query_tree(1,0,n-1,a-1,b-1));else if (c=='U')update_tree(1,0,n-1,a-1,b);}}
}
總結
以上是生活随笔為你收集整理的线段树——入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。