Segment tree + multiple lazy Tags: maintain sequence

Posted by amcgrath on Tue, 28 Dec 2021 14:42:15 +0100

Title Link: https://www.luogu.com.cn/problem/P2023

analysis:

Node of segment tree:

struct Node

{

int l,r;

int add; // Lazy mark addition

int mul; / / lazy mark multiplication

int sum; // Really required value

}

1. How to update sum value through attribute.

, how to update the sum value through add and mul is similar to the idea of constructing node attributes in the question "can you answer these questions" in the previous segment tree, Can you answer these questions , in order to calculate the corresponding value, many attributes are added.

How to get the sum attribute we need through the add and mul attributes? You can find out what kind of maintenance method is available

(sum + add) * mul, (that is, each addition operation is converted to storing add and mul, and then finally calculated in this way). In this way, the multiplication modification is easy to modify. (sum + add) * mul * c

So just change the previous mul to {mul * c. But what about addition?

(sum + add) + mul + d. at this time, it will be found that this maintenance method cannot update the add lazy tag attribute value of the parent node through the child node.

So do you want to add a new attribute to the question "can you answer these questions"?

In fact, it's not necessary. We can calculate sum in another way

sum * mul + add,

Multiplication: ((sum * mul) + add) * m;

Then mul is changed to mul * m and add is changed to add * m

Addition: sum * mul + add + m, so add can be changed to add + M.

So it can be easily maintained.

At the same time, there is another skill. Our topic has two modification operations, addition modification and multiplication modification,

Do you need to use different functions to operate on it?   

Actually, it's not necessary,

Sum * a can be converted to sum * a + 0

sum + b can be converted to sum * 1 + b;

Therefore, both multiplication modification and addition modification can be changed to multiplication and addition modification.

Finally, carry out the corresponding operation

Push up(), modify the sum value of the parent node, root sum = leftson. sum + right. sum

pushdown, 

According to the formula (sum * a + b) * C + D = = sum * a * c + b * c + d;

Therefore, a root node, add value and mul value can be modified

sum = sum * mul + (r - l + 1) * d;

mul = mul * c;

add   = add * mul + d

Other operations remain basically the same.

Lazy mark template problem solution

Code implementation:

# include <iostream>
using namespace std;

const int N = 100010;

int a[N];

struct Node
{
    int l,r;
    int sum;
    int add;
    int mul;
}edgs[N * 4];

int n,m,p;

void pushup(int u)
{
    edgs[u].sum = (edgs[2 * u].sum + edgs[2 * u +1].sum) % p;
}

void eval(int root , int d,int m) //Update the root node with new lazy tags such as add,mul, and new sum value
{
    edgs[root].sum = ( (long long)m * edgs[root].sum  +(long long)(edgs[root].r - edgs[root].l +1 ) * d ) % p; // It should be noted that the interval is modified, and the whole interval is added with the add value
    edgs[root].mul = (long long)edgs[root].mul * m % p;
    edgs[root].add =  ( (long long)edgs[root].add * m + d ) % p;
}

void pushdown(int u)
{
    //Drop the value corresponding to the lazy tag to the child node
    eval(2 * u , edgs[u].add , edgs[u].mul);
    eval(2 * u + 1 , edgs[u].add , edgs[u].mul);

    // Clear lazy tag operation of root node
    edgs[u].add = 0;
    edgs[u].mul = 1;
}

void build(int u , int l , int r)
{
    edgs[u].l = l, edgs[u].r = r, edgs[u].add = 0 , edgs[u].mul = 1;
    if(l == r)
    {
        edgs[u].sum  = a[l];
        return;
    }
    else
    {
        int mid = ( edgs[u].l + edgs[u].r ) / 2;
        build(2 * u , l , mid);
        build(2 * u +1 , mid + 1 , r);
        //Not the edgs [u] of the leaf node The attribute value of sum is generated by pushup. So they can be assigned or not
        pushup(u);
    }
}

void modify(int u , int l , int r , int add , int mul)
{
    if(edgs[u].l >=  l && edgs[u].r <= r)
    {
        eval(u,add,mul);
        return;
    }
    else
    {
        pushdown(u);
        int mid = ( edgs[u].l + edgs[u].r ) / 2;
        if(l <= mid)
        {
            modify(2 * u ,l , r , add , mul);
        }
        if(r > mid)
        {
            modify(2 * u + 1 , l , r,  add , mul);
        }
        pushup(u);
    }
}

int query(int u , int l ,int r)
{
    if(edgs[u].l >= l && edgs[u].r <= r)
    {
        return edgs[u].sum;
    }
    else
    {
        pushdown(u);
        int mid = ( edgs[u].l + edgs[u].r ) / 2;

        int sum = 0;

        if(l <= mid)
        {
            sum = query(2 * u , l , r) % p;
        }
        if(r > mid)
        {
            sum =( (long long)sum + query(2 * u +1 , l , r) ) % p;
        }
        return sum;
    }
}

int main()
{
    scanf("%d %d",&n,&p);
    for(int i = 1 ; i <= n ; i++)
    {
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    scanf("%d",&m);
    while(m--)
    {
        int a;
        scanf("%d",&a);;
        if(a == 1)
        {
            int t ,g,c;
            scanf("%d %d %d",&t,&g,&c);
            modify(1,t,g,0,c); // Multiplication operation, so add = = 0, Mul = C
        }
        else if(a == 2)
        {
            int t ,g,c;
            scanf("%d %d %d",&t,&g,&c);
            modify(1,t,g,c,1); // Add operation, so add = = C, Mul = 1
        }
        else
        {
            int t,g;
            scanf("%d %d",&t,&g);
            printf("%d\n",query(1,t,g));
        }
    }
    return 0;
}

Topics: data structure