線段樹是一顆二叉樹,每乙個結點維護一段區間。因為是二叉樹,所以可以用p*2表示p的左兒子,p*2+1表示p的右兒子。
struct node
t[maxn<<2];//線段樹要開四倍空間
給定長度為n的陣列a(下標從1開始)。
對區間[1,n]上的值建一顆線段樹。
#define lson p*2
#define rson (p*2+1)
void up(int p)
void build(int p,int l,int r)//p表示結點編號,l、r表示結點p所表示的區間
int mid=(l+r)>>1;
build(lson,l,mid); //遞迴建立左子樹
build(rson,mid+1,r); //遞迴建立右子樹
up(p); //由下向上傳遞資訊,即由兩個小區間合併成乙個大區間
}
將第k個元素的值改為v。
遞迴找到葉子結點,修改葉子結點的值,然後用up函式向上修改包含該葉子結點的區間。
void update(int p,int k,int v)
int mid=(t[p].l+t[p].r)>>1;
if(k<=mid) update(lson,k,v); //k葉子結點在左子樹上
else update(rson,k,v); //k葉子結點在右子樹上
up(p); //修改包含結點的區間
}
查詢區間[x,y]的資訊。
將區間[x,y]分成若干小份區間,每乙個區間恰好與線段樹上某乙個結點所表示的區間對應,獲取該結點的資訊並最終將若干個小份區間資訊整理即可。
#define inf 0x3f3f3f3f
int query(int p,int x,int y)
}
如果像單點修改一樣去修改每乙個葉子的話,時間複雜度無法接受。所以引入延遲標記mark的概念。
比如說要修改區間[x,y],恰好乙個結點p所表示的區間就是[x,y],那麼修改了p的資訊就夠了,p的子樹的結點資訊暫不修改。但是僅僅是暫時不修改,當你需要去查詢或者修改p的子樹結點的資訊時,就要先根據延遲標記mark修改了資訊後再進行其他操作。
void update(int p,int x,int y,int v)
//區間在p的子樹結點中,要呼叫子樹結點資訊,必須先下傳延遲標記
down(p); //下傳標記將p的左右子結點修改,只修改了這兩個結點,延遲標記放在了這兩個結點上
int mid=(t[p].l+t[p].r)>>1;
if(y<=mid) //區間[x,y]一定在左子樹上
update(lson,x,y,v);
else
if(x>mid) //區間[x,y]一定在右子樹上
update(rson,x,y,v);
else
up(p);
}
線段樹小結
按照牛的部落格寫了幾道題,刷了一周效果不錯 1.複習鞏固了以前的知識 2.還有改正了一些寫線段樹毛病 3.改正了在弱資料的影響下的錯誤方法ac的題目 4.還學到了線段樹新的型別題 總體效果不錯,總結一下 poj 2892 最直觀的是平衡樹,用樹狀陣列的findk的功能更酷一些,線段樹找第k小也可以,...
線段樹小結
實際上還是稱為區間樹更好理解一些。樹 是一棵樹,而且是一棵二叉樹。線段 樹上的每個節點對應於乙個線段 還是叫 區間 更容易理解,區間的起點和終點通常為整數 同一層的節點所代表的區間,相互不會重疊。同一層節點所代表的區間,加起來是個連續的區間。葉子節點的區間是單位長度,不能再分了。線段樹的深度不超過l...
線段樹小結
線段樹基本概念 線段樹結構 線段樹和區間 線段樹性質 向上取整 這樣在進行更新查詢操作的時候,操作的複雜度就可以為log n 量級 葉子節點的數目和根節點表示的區間長度相同 若葉子節點的數目為n,則線段樹的總節點數目為2 n 1。因為線段樹的節點要麼是0度,要麼為2度,根據二叉樹的性質可知。線段樹操...