Advanced guide to algorithm competition---0x43 (line segment tree) interval GCD

Topic

Insert picture description here

answer

  1. Two operations, add a number to an interval, query the greatest common divisor of the interval, we know that for the line segment tree without lazy mark, only single-point modification and interval query can be done. If you want to query the interval, you must add lazy Mark, but we think about it carefully. There is only one interval modification operation in the question. Add a number to each number in a range. Is it very familiar? Yes, it is the difference.
  1. We can use the difference array, we only need to modify the left and right endpoints of the interval to modify all the numbers in the interval. Set the b array as a difference array, and add a c to the original array interval [l,r] to become b[ l]+=c, b[r+1]+=c;
  1. For the greatest common divisor of the query interval,We know that the greatest common divisor of an interval is gcd( al, al+1, al+2 ,... ar), but now it is the difference, we can transform it into gcd(al, al+1-al, al +2 -al+1 ,…ar-ar-1)(I don’t know the nature of Baidu on my own ), then the greatest common divisor of an interval is gcd(al) ,gcd(al+1-al, al +2-al+1 ,…ar-ar-1) these two Partial composition, for the first part, al = b1+b2 +b3 +…+ bl (the sum of the sum difference array interval must be present in the node of the line segment tree)
    For the second part, the interval difference array is a gcd

Code

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
typedef long long ll;
const int N = 5e5 + 10;

int n, m;
ll w[N];

struct Node {
    
    
    ll l, r;
    ll sum;
    ll d;
} tr[N * 4];

ll gcd(ll a, ll b) {
    
    
    return b ? gcd(b, a % b) : a;
}

void pushup(Node &u, Node &l, Node &r) {
    
    
    u.sum = l.sum + r.sum;
    u.d = gcd(l.d, r.d);
}

void pushup(ll u) {
    
    
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(ll u, ll l, ll r) {
    
    
    if (l == r) {
    
    
        ll b = w[l] - w[l - 1];
        tr[u] = {
    
    l, r, b, b};
    } else {
    
    
        tr[u] = {
    
    l, r};
        ll mid = (l + r) >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void modify(ll u, ll x, ll v) {
    
    
    if (tr[u].l == x && tr[u].r == x) {
    
    
        ll b = tr[u].sum + v;
        tr[u] = {
    
    x, x, b, b};
    } else {
    
    
        ll mid = (tr[u].l + tr[u].r) >> 1;
        if (x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
}

Node query(ll u, ll l, ll r) {
    
    
    if (l <= tr[u].l && tr[u].r <= r) return tr[u];
    else {
    
    
        ll mid = (tr[u].l + tr[u].r) >> 1;
        if (r <= mid) return query(u << 1, l, r);
        else if (l > mid) return query(u << 1 | 1, l, r);
        else {
    
    
            Node res;
            auto left = query(u << 1, l, r);
            auto right = query(u << 1 | 1, l, r);
            pushup(res, left, right);
            return res;
        }
    }
}

int main() {
    
    

    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%lld", &w[i]);

    build(1, 1, n);

    while (m--) {
    
    
        string op;
        ll l, r, d;
        cin>>op;
        if (op == "C") {
    
    
            cin >> l >> r >> d;
            modify(1, l, d);
            if (r + 1 <= n) {
    
    
                modify(1, r + 1, -d);
            }
        } else {
    
    
            cin >> l >> r;
            auto left = query(1, 1, l);
            auto right = query(1, l + 1, r);
            cout << abs(gcd(left.sum, right.d)) << endl;
        }
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_44791484/article/details/113838536