From "algorithm contest Advanced Guide."
Segment tree is based on the idea of divide and conquer binary tree for statistical information on the range.
The basic features of the segment tree:
each node of the tree represents 1. a segment interval.
2. interval segment tree with a unique root node represents the entire range of statistics, such as [1, N].
3. Each leaf node of the tree represents a segment length of meta interval [x, x] 1 is.
4. For each internal node [l, r], its left child node [l, mid], the right child node [mid + 1, r], where mid = (l + r) / 2 ( down Rounding).
Method segment tree node number: "father twice" node numbering
1. root numbered 1.
2. The number of the left child node number of node x x * 2, the right child node number x * 2 + 1.
Note: Save the tree line array length is less than either 4N to ensure not out of range. (N leaf nodes)
The basic operation of the segment tree (interval maximum value to maintain Example)
Segment tree of achievements
- It creates a segment tree and the maximum value stored in the corresponding section on each node.
struct SegmenTree {
you to, to;
you dat;
T} [N * . 4 ]; // struct array storage segment tree
void build(int p,int l,int r){
T [p] .L = L, T [p] .r = R & lt; // node p represents an interval [L, R & lt]
IF (L == R & lt) {T [p] .dat A = [L]; return ;} // leaf node
int MID = (L + R & lt) / 2 ; // binary
Build (P * 2 , L, MID); // left child node [l, mid], No. 2 * P
Build (P * 2 + . 1 , MID + . 1 , R & lt); // right child node [mid + 1, r], No. 1 + 2 * P
T [P] .dat = max (T [P * 2 ] .dat, T [P * 2 + . 1 ] .dat); // up information transmitted from the
}
Build ( . 1 , . 1 , n-); // call inlet
Single-point segment tree changes
- The a [x] modify the value v, the time complexity: O (log N).
Line segment tree, the root node (Node No. 1) is to perform various instructions inlet. We need to start from the root, recursively find the leaf nodes represent the interval [x, x], and then up the updating information stored on [x, x] and all its ancestor nodes from under.
void Change ( int P, int X, int V) { IF .dat = V (T [P] == T .L [P] .r) {T [P]; return ;} // find the leaf node int = MID (T [P] .L + T [P] .r) / 2 ; IF (X <= MID) Change (* P 2 , X, V); // X belonging to a left half section the else Change (* P 2 + . 1 , X, V); // X belongs right interval T [P] .dat = max (T [P * 2 ] .dat, T [P * 2 + . 1 ] .dat); // from up update information } Change ( . 1 , X, V); // call inlet
Range segment tree of query
- A maximum value of the query sequence in the interval [l, r] of.
Starting from the root, the following recursive procedure:
1. If [l, r] completely covers the interval represented by the current node, backtracking immediately, and the node value dat candidate answer.
2. If the left child node and [l, r] has an overlapping portion, the left child node recursively visit.
3. If the right child node, and [l, r] overlap section, then descend the right child node.
int ASK ( int P, int L, int R & lt) { IF (<T = [P] && R & lt .L> T L = [P] .r) return T [P] .dat; // completely contained int MID = (T [P] .L + T [P] .r) / 2 ; int Val = - ( . 1 << 30 ); // negative infinity IF (L <= MID) Val = max (Val, ASK (P * 2 , L, R & lt)); // the left child node overlap IF (R & lt> MID) Val = max (Val, ASK (P * 2 + . 1 , L, R & lt)); // right child nodes overlap return Val; } COUT << ASK ( . 1 , L, R & lt) << endl; // call inlet
The query procedure the interrogation interval [l, r] into the segment tree green O (log N) nodes , takes a maximum value thereof as the answer.
Reason: At each node [P L , P_R], the set = MID (P L + P R & lt ) / 2 (rounded down), the following situations may occur:
1.l≤p L ≦ P R & lt ≤r, that is completely covered by the current node, direct return.
2.P l ≤l≤p R & lt ≤R, i.e. in the node is only l.
(1) l> mid, only recursively right subtree.
(2) l≤mid, although the two sub-tree recursively, but returns the right child node directly after the recursion.
3.l≤p L ≤r≤p r , i.e., r is only in the node, similarly to the case 2.
4.p l ≤l≤r≤ r , i.e., r and l are in among nodes.
(1) l, r are located on one side of mid, only recursive subtree.
(2) l, r are located on both sides of the mid recursively about two subtrees.
- Only 4 cases (2) will actually generate a recursive for about two sub-tree. This occurs at most once, then it will become in the case of 2 or 3 child nodes. Thus, the query time complexity of the above-described process is O (2logN) = O (log N).
[1] example: you can answer these questions it
[example 2]: Interval greatest common divisor
Delayed mark (the face of the interval modification)
When we modify instruction, can l≤p L ≤ P L returned the case ≤r immediately, but before backtracking to increase p tag node, identifies "the node had been modified, but its children has not been updated." .
In a subsequent instruction, recursively downward from the node p, we check whether the flag p. If labeled, according to two child nodes labeled p updated information, while increasing the two child nodes labeled p, and p clear indicia.
Thus, the time complexity of each instruction is modified from O (N) down to O (log N).
[Example]: a simple integer problems
main code is as follows:
#define 100000+10
struct N SegmentTree{
int l,r;
long long sum,add;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define add(x) tree[x].add
#define sum(x) tree[x].sum
}tree[N*4];
int a[N],n,m;
void build(int p,int l,int r){
l(p)=l,r(p)=r;
if(l==r){sum(p)=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
sum(p)=sum(p*2)+sum(p*2+1);
}
void Spread ( int p) {
IF (the Add (p)) { // node p marked
SUM (p * 2 ) + = the Add (p) * (R & lt (p * 2 ) -l (p * 2 ) + . 1 ); // update information left child node
SUM (P * 2 + . 1 ) + = the Add (P) * (R & lt (P * 2 + . 1 ) -l (P * 2 + . 1 ) + . 1 ); // update the right child node
the Add (P * 2 ) + = the Add (P); // play delay marker to the left child node of
the Add (P * 2 + . 1 ) + = the Add (P); //To the right child playing flag delay
the Add (P) = 0 ; // clear the flag b
}
}
void Change ( int P, int L, int R & lt, int D) {
IF (L <= L (P) && R & lt> = R & lt (P)) { // completely covered
SUM (P) + = ( Long Long ) D * (R & lt (P) -l (P) + . 1 ); // update the node information
the Add (P) = D +; // to delay playing the node labeled
return ;
}
Spread (P); // downstream delay flag
int MID = (L (P) R & lt + (P)) / 2 ;
IF (L <= MID) Change (* P 2 , L, R & lt, D);
IF ( R & lt> MID) Change (* P 2 + . 1 , L, R & lt, D);
sum(p)=sum(p*2)+sum(p*2+1);
}
long long ask(int p,int l,int r){
if(l<=l(p)&&r>=r(p))return sum(p);
Spread (P); // downstream delay flag
int MID = (L (P) + R & lt (P)) / 2 ;
Long Long Val = 0 ;
IF (L <= MID) Val + = ASK (P * 2 , L , R & lt);
IF (R & lt> MID) ASK = Val + (P * 2 + . 1 , L, R & lt);
return Val;
}
int main () {
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m--){
char op[2];int l,r,d;
cin >> >> l >> r;
if (in [ 0 ] == ' C ' ) {
cin>>d;
change(1,l,r,d);
}
else cout<<ask(1,l,r);
}
}
Scan line
[1] example: Atlantis
[2] example: the stars in the window