Tree-like array

Source: Internet
Author: User

Tree-like array

Turn from: by rock trace http://blog.csdn.net/zearot/article/details/45028723

I. Overview

A tree-like array is a multi-fork tree that is stored from the bottom up with an array.

In the following narrative, a is the original array, C is the array used for the tree array, and B is the auxiliary array to be used for the special case.

The most basic application is to maintain a sequence that supports two operations: 1. Let A[i] Add a certain number X 2. Ask for an interval a[l] + a[l+1] + ... + a[r] and.

A tree array can do two operations with a time complexity of O (log2 (n)) and is generally faster than a segment tree.

The index of the tree array starts at 1.

Second, the achievements (in the figure of the n=11 array as an example of achievements)

Make each element of the C array equal to the A array, at which point C is called the first row, see: (Operation 11 times)

Then put the first line of C, the odd items do not move, even items each add their own previous item. C[2]+=C[1],C[4]+=C[3], c[6]+=c[5] ... (Operation 5 times) See:

The first line is the value of the final C array, then the same operation on the second line, that is, even items are added to their previous item, C[4]+=C[2],C[8]+=C[6],..... (Operation 2 times) See:

The remaining number in the second line is also the final C value, and then the third line does the same thing: c[8]+=c[4] ... (Operation 1 times) is the final form of the array, it is obvious that this is a root-free multi-fork tree.

Figure one: The tree-like array after the n=11 is built

Achievement Code:

void Build (int n) {//runs the function before each number of C arrays equals the number of an array of    x=2,halfx=1 int;    while (X <= N) {for    (int i=x;i<=n;i+=x) {    c[i]+=c[i-halfx];    }    X <<= 1; Halfx <<= 1;    }}

This is theoretically 2*n-count_bits (n), where Count_bits (n) returns the number of binary representations of N of 1.

For the case of n=11 2*11-count_bits (11) = 19 times. If you do not keep an array of a, the array of a directly becomes a C array, then the number of operations is N-count_bits (n) (less the first n assignment).

In short, O (n) achievements.

However, it is generally simpler to simply empty the C array and then call the N-times Add (I,a[i]) function, so that the time complexity is O (N*LOG2 (n)).

Strangely enough, the first method is slower than the second and not figured out when testing the problem with HDU1166 (point change interval query).

However, it is good to do so, for example, when doing dynamic interval K, a tree array can be used to persist the line tree of the method,

So the space consumption is significantly less than the call N times Add. Or, if the maintenance of the nature of the "addition" is time-consuming, you can also consider the direct achievements.

Third, Add function (Modify an item)

The first step is to understand how to modify the above array (in the diagonal line up, passing the node to be modified).

Take a look at the last picture above:

Note that:

The subscript of line 1th C is 1* (1,3,5,7,...) The parent node of 1 is 2. The parent node of 3 is 4. The parent node of 5 is 6. The parent node of 7 is 8. The parent node of 9 is 10. Each C has a number of 1 a

The subscript for 2nd row C is (1,3,5,7,..) After the subscript is removed 2, 1 of the parent node is 2.                                                             The parent node of 3 is 4. Each C saved 2 A in the number of a

3rd row C subscript for the 1,3,5,7 (...)                                                                                  After the subscript is removed 4, 1 of the parent node is 2. Each C saved 4 A in the number of a

The subscript for line C of K+1 is 2^k* (1,3,5,7.) subscript after 2^k, 1 of the parent node is 2. 3 of the parent node is 4, and so on, each C has a number of 2^k a.

Now the problem is getting a subscript x, how to find the parent node of x (because updating x, you have to update the parent of X)

Assuming x = (2^k) * An odd number, then according to the above rule, the parent node subscript of X is actually: (an odd number +1) * (2^k) = an odd number * (2^k) + (2^k) = x+ (2^k)

So as long as you find this by X (2^K) can find the parent node of x, and the tree array of important functions lowbit just can be found (2^k)

That is, if x = (2^k) * An odd number then lowbit (x) = 2^k (see section V for this part: Lowbit function)

So it's not ugly to understand the following add code:

void Add (int x,int c) {if (!x) return;//prevents a dead loop while (x <= N) {a[x]+=c;x+=lowbit (x);}}


Four: Sum function (sums of the first X items)

The number of X nodes saved in sum is Lowbit (x),

C[x]=a[x-lowbit (x) +1] + a[x-lowbit (x) +2] +. +A[X-1]+A[X]

So the result is added c[x], followed by to find the value of A[x-lowbit (x)], so it is not ugly to understand the following sum code:

int Sum (int x) {///ex x and    int ans=0;   while (x>0) {   ans+=a[x];   X-=lowbit (x);   }    return ANS;}


V: lowbit function

The first is the definition of lowbit:

int lowbit (int x) {return   x& (-X);}

The ~i in the figure is reversed by the position of I, since the number in the machine is in complement, so-i = (~i) +1

x& (-X) can naturally find out the Lowbit (x).

Vi. time complexity and space complexity

Make K1=x+lowbit (x). K2=x-lowbit (x). Easy to get Lowbit (K1) > x and Lowbit (K2) > x.

That is, K1 and K2 are at least higher than X, the number of layers in X is increasing, and the total number of floors is floor (log2 (n)) +1 so the add and sum operations are O (log2 (n)).

In comparison with the line tree, the modification of the segment tree changes almost to floor (LOG2 (n)) + 1 nodes,

The tree array is changed up to Floor (LOG2 (n)) +1 nodes, at least 1 nodes are changed (such as n=11 change A[8])

The advantages of a tree array the first is fast, the second is that it really is only 1 time times the space, do not need to expand up to 2 of a certain point.

Line tree is to first expand the N up to the smallest of a 2 of the sub-side, and then multiply by a 2 (generally for the sake of convenience directly open 4*n array).

In the power of statistics, it is not quite right to use a non-recursive line tree to save half of space (save All right subtrees) and use one-fold space.

Even non-recursion needs to be expanded up to a minimum of 2 of the sub-side.

The number of array elements required to omit half of the space for a non-recursive segment tree is:

And its scope is shown on the right-hand formula:

So it is necessary to expand a certain amount of space, n arrays of elements is not enough.

For convenience, direct expansion to a minimum of 2 greater than the second side of the line (save half the space, but also can only seek prefixes and, can not directly seek the interval and).

Attach a non-recursive line tree code that saves half of the space:

 
int n;int a[maxn],sum[maxn];int sum (int x) {///ex x and     int ans=0;    for (int t=x+n;t^1;t>>=1) {        if (t&1) ans+=sum[t/2];//is to access the node t^1 before the space is omitted, since the t^1 must be an even number, use (t^1)/2 = t/ and storage of the original t^1 node content </span>    }//Because of this, all odd nodes are not accessed, so the odd nodes are all saved (save half the space). </span>    return ANS;} void Add (int x,int c) {for (int t=x+n-1;t^1;t>>=1) {if (~t&1) sum[t/2]+=c;}} void Build (int n) {//n number of elements, stores the array in a, and then calls Build to use the add and SUM functions normally n=1;while (n <= N) n <<= 1;memset (sum,0, sizeof (sum));    for (int i=1;i<=n;++i) ADD (I,a[i]);}

Again, the efficiency of tree-like arrays:

The number of operations that were created by filtering out the even numbers at the same time as the previous picture

And the number of times the direct use of the N add function is:, this formula seems to have no way to simplify.

But each item is about equal to N/2, a total of not 0 items, so the total complexity is

Vii. Other uses of tree-like arrays
The first type: Interval modification, point query

Thought is actually the change of the interval to point modification, do not use C[i] array.

Adds an array of B. Assuming b[i]=t, it means that the interval a[i],a[i+1],..., a[n] is increased by T.

Then, the operation of adding X to the number of intervals [l,r] is changed to two points: B[l]+=x and b[r+1]-=x;//Here are shorthand, and they need to update their parent node

Then query point X, ask B[1]+b[2]+...+b[x] and plus a[x], because the changes on these points will affect the X.

The second type: interval modification, interval query

Here is a little bit of math, using a[i] to represent a[i]-a[i-1] (assuming a[0]=0)

Use s[i] to denote a[1]+a[2]+...+a[i], with P[i] for A[1]+2*a[2]+3*a[3]+...+i*a[i]

Prefix and prefix and ss[x]=s[1]+s[2]+s[3]+...+s[x]=n*a[1]+ (n-1) *a[2] +...+2*a[x-1] + a[x] = (n+1) s[x]-p[x]

So as long as the differential sequence maintenance s[i] and P[i] Two properties are good.

S[i] to maintain the prefix and (=a[i]) of the original array a[i], P[i] to maintain the prefix of the original array i*a[i] and

If the interval is modified, A[L]-A[L-1] has more x. A[r+1]-a[r] less x.  That is a[l]+=x. A[r+1]-=x; Two-point modification

Each point has to modify S and p two arrays.

The code is as follows:

 
#define LL Long long#define maxn 100001int n,q; LL A[MAXN]; ll P[maxn],s[maxn];void ADDP (ll X,ll v) {if (!x) return;while (x <=n) {p[x]+=v;x+=x&-x;}} void AddS (ll X,ll v) {if (!x) Return;while (x <=n) {s[x]+=v;x+=x&-x;}} ll Sump (ll x) {ll ans=0;while (x>0) {ans+=p[x];x-=x&-x;} return ans;} ll SumS (ll x) {ll ans=0;while (x>0) {ans+=s[x];x-=x&-x;} return ans;} void INC (LL l,ll r,ll c) {//zone [L,r] plus C AddS (l,c); AddS (R+1,-C); ADDP (L,L*C); ADDP (r+1,-(r+1) *c);} ll QUE (ll a) {//ask for prefix and return (a+1) *sums (a)-sump (a);}



The third type: two-dimensional tree-like array

A two-dimensional tree array is the ability to find and change the value of a rectangular region of a matrix within a time.

If you understand a one-dimensional tree array, think twice about the two-dimensional situation.

 
int N;int a[1002][1002];void Add (int x,int y,int k) {//a[x][y] Add K while (x <= n) {int yy=y, while (yy <= n) {a[x][yy]+=k; yy+=yy&-yy; }x+=x&-x;}} int Sum (int x,int y) {//I<=x,j<=y all elements of the matrix and int ans=0;while (x > 0) {int yy=y;while (yy > 0) {ans+=a[x][yy];yy-=yy &-yy;} X-=x&-x;} return ANS;}

Viii. Conclusion

Previously learned the line segment tree, heard that the tree-like array function than the segment tree, has not learned, until the dynamic interval to check the first K-large, the tree array set of the Chairman tree

So decided to learn the tree array, and then found that the tree array is very useful, the code is simple and efficient, only open n space does not need to be expanded.

The efficiency of non-recursive line segment tree is actually similar, but non-recursive line tree to carry out a complex subscript transformation, every write to want half a day,

Or a tree-like array is simple to write, so you can write a tree-like array to avoid writing complex line tree.

Tree-like array

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.