Detailed line segment tree

The line segment tree has a simple idea and a slightly longer code, which will not bring bad feelings to readers. Please eat it with confidence (funny)

Okay, let's go back to the topic, the line segment tree is a binary tree, and its purpose is to maintain a sequence of numbers, so how to maintain it? Its idea is similar to divide and conquer. First, each node of this tree has two attributes, l and r, which represent the scope of its own management, then the root of this tree, its l and r are naturally 1 and n (n is the length of the sequence), and then, each node has two sons, each of which manages 1/2 of the range to be managed. Take the root node as an example, the root node needs to manage 1~n, then its left son Just manage 1~n/2, the right son manages n/2+1~n, and then record who your left and right sons are, and the tree is built. For example, if there is a sequence n=4, then the built tree is It looks like this:


It can be found that after the tree is built, the management scope of the leaf node is only one, so they only manage the number in that position in the sequence.

tree building code:

void buildtree(int x,int y)
{
    len ++;
    tree[len].l=x;
    tree[len].r=y;
    tree [len] .zuo = tree [len] .you = -1;
    tree[len].late=0;//late mark will be discussed below
    if(x==y)tree[len].sum=a[x];//sum represents the sum of the numbers within the range it manages in the sequence
    else
    {
        int now=len;
        int mid=(x+y)/2;//Distribute your management interval to two sons (points)
        tree[now].zuo=len+1;buildtree(x,mid);
        tree[now].you=len+1;buildtree(mid+1,y);
        tree[now].sum=tree[tree[now].zuo].sum+tree[tree[now].you].sum;//Get your own value from the son's value (merge)
    }
}

Modification and query (here takes interval sum as an example):

Modification: When modifying, we only need to check whether the interval to be modified is on the left son or the right son of the current node. If it is only on a certain son, then just modify that son directly, but if it is on two All the sons have them, so just throw those managed by the left son to the left son, and those managed by the right son to the right son.

For example, currently we need to make the 1~2 interval + x, then first start from the root node, find that 1~2 are all in the management scope of the left son, so go to the left son of the root, and then find the management scope of the left son Just right is the range to be modified, then at this time, we don't need to continue, we just need to late+x this point, and when we visit this node next time, we'll put its late Just throw the value to the son, then the time complexity of modification can be optimized from O(nlogn) to O(metaphysics). . .

code show as below:

void change(int now,int x,int y,ll z)//now indicates which node of the line segment tree is now, x and y indicate the modification range
{
    if(tree[now].l==x&&tree[now].r==y)//The management scope is just equal to the modification scope
    {
        tree[now].late+=z;
        give(now);//Assign down
        return;
    }//If the management scope of this point is larger than the modification scope
    give(now);
    int zuo=tree[now].zuo,you=tree[now].you;
    int mid=(tree[now].l+tree[now].r)/2;
    if(y<=mid)change(zuo,x,y,z);//If in the left son
    else if(x>=mid+1)change(you,x,y,z);//If in the right son
    Else//Add on both sides, just modify each
    {
        change(zuo,x,mid,z);
        change(you,mid+1,y,z);
    }
    tree[now].sum+=z*(y-x+1);//! ! ! If you have (y-x+1) sons and add z, then add (y-x+1)*z to your sum value
}

Inquire:

The query and modification are almost the same, just look at the code directly:

ll print(int now, int x, int y)//x, y indicates the interval sum from x to y
{
    give(now);//Assign it, you must assign it first, think about it and know why
    if(tree[now].l==x&&tree[now].r==y)return tree[now].sum;//If the required interval happens to be the interval managed by this node, then just return its sum All right
    int zuo=tree[now].zuo,you=tree[now].you;
    int mid=(tree[now].l+tree[now].r)/2;//Otherwise continue to look down
    if(y<=mid)return print(zuo,x,y);
    else if(x>=mid+1)return print(you,x,y);
    else return print(zuo,x,mid)+print(you,mid+1,y);
}

Finally, add the give function:

void give(int x)
{
	int zuo=tree[x].zuo,you=tree[x].you;
	tree[x].sum+=(tree[x].r-tree[x].l+1)*tree[x].late;//All numbers within your own management range are added with tree[x]. late, then your own value will naturally be added (management range *tree[x].late)
	if(zuo!=-1)//If you have a son, assign your late
	{
		tree[zuo].late+=tree[x].late;
		tree[you].late+=tree[x].late;
	}
	tree[x].late=0;//Clear the late tag
}

This is the template of the line segment tree, if you have any questions, you can leave a message in the comment area

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324839430&siteId=291194637