线段树简介
1.構造 void build(int node, int begin, int end);
主要思想是遞歸構造,如果當前節點記錄的區間只有一個值,則直接賦值,否則遞歸構造左右子樹,最后回溯的時候給當前節點賦值
#include <iostream> using namespace std; const int maxind = 256; int segTree[maxind * 4 + 10]; int array[maxind]; /* 構造函數,得到線段樹 */ void build(int node, int begin, int end) { if (begin == end) segTree[node] = array[begin]; /* 只有一個元素,節點記錄該單元素 */ else { /* 遞歸構造左右子樹 */ build(2*node, begin, (begin+end)/2); build(2*node+1, (begin+end)/2+1, end); /* 回溯時得到當前node節點的線段信息 */ if (segTree[2 * node] <= segTree[2 * node + 1]) segTree[node] = segTree[2 * node]; else segTree[node] = segTree[2 * node + 1]; } } int main() { array[0] = 1, array[1] = 2,array[2] = 2, array[3] = 4, array[4] = 1, array[5] = 3; build(1, 0, 5); for(int i = 1; i<=20; ++i) cout<< "seg"<< i << "=" <<segTree[i] <<endl; return 0; }
2.區間查詢int query(int node, int begin, int end, int left, int right);
(其中node為當前查詢節點,begin,end為當前節點存儲的區間,left,right為此次query所要查詢的區間)
主要思想是把所要查詢的區間[a,b]劃分為線段樹上的節點,然后將這些節點代表的區間合并起來得到所需信息
int query(int node, int begin, int end, int left, int right) { int p1, p2; /* 查詢區間和要求的區間沒有交集 */ if (left > end || right < begin) return -1; /* if the current interval is included in */ /* the query interval return segTree[node] */ if (begin >= left && end <= right) return segTree[node]; /* compute the minimum position in the */ /* left and right part of the interval */ p1 = query(2 * node, begin, (begin + end) / 2, left, right); p2 = query(2 * node + 1, (begin + end) / 2 + 1, end, left, right); /* return the expect value */ if (p1 == -1) return p2; if (p2 == -1) return p1; if (p1 <= p2) return p1; return p2; }
3.區間或節點的更新 及 線段樹的動態維護update
單節點更新
void Updata(int node, int begin, int end, int ind, int add)/*單節點更新*/ { if( begin == end ) { segTree[node] += add; return ; } int m = ( left + right ) >> 1; if(ind <= m) Updata(node * 2,left, m, ind, add); else Updata(node * 2 + 1, m + 1, right, ind, add); /*回溯更新父節點*/ segTree[node] = min(segTree[node * 2], segTree[node * 2 + 1]); }
區間更新(線段樹中最有用的)
void Change(node *p, int a, int b) /* 當前考察結點為p,修改區間為(a,b]*/ { if (a <= p->Left && p->Right <= b) /* 如果當前結點的區間包含在修改區間內*/ { ...... /* 修改當前結點的信息,并標上標記*/ return; } Push_Down(p); /* 把當前結點的標記向下傳遞*/ int mid = (p->Left + p->Right) / 2; /* 計算左右子結點的分隔點 if (a < mid) Change(p->Lch, a, b); /* 和左孩子有交集,考察左子結點*/ if (b > mid) Change(p->Rch, a, b); /* 和右孩子有交集,考察右子結點*/ Update(p); /* 維護當前結點的信息(因為其子結點的信息可能有更改)*/ }
?
?摘自:http://blog.csdn.net/metalseed/article/details/8039326
轉載于:https://www.cnblogs.com/gaoss/p/4963294.html
總結
- 上一篇: 胆囊息肉手术费大概多少钱?
- 下一篇: iOS 对UIImage进行的一些操作