AcWing 246. 区间最大公约数 [线段树,单点修改]

原题链接

题目描述

给定一个长度为 NN 的数列 AA,以及 MM 条指令,每条指令可能是以下两种之一:

  1. C l r d,表示把 A[l],A[l+1],,A[r]A[l],A[l+1],…,A[r] 都加上 dd
  2. Q l r,表示询问 A[l],A[l+1],,A[r]A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

对于每个询问,输出一个整数表示答案。

<br class="more">

输入格式

第一行两个整数 N,MN,M

第二行 NN 个整数 A[i]A[i]

接下来 MM 行表示 MM 条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

N500000,M100000N≤500000,M≤100000,
1A[i]10181≤A[i]≤1018,
|d|1018|d|≤1018

 

输入样例:

5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4

输出样例:

1
2
4

解题思路

思路1:直接维护区间修改的线段树

思路2:维护单点查询的线段树,我们主要讲这种思路

可以证明gcd(a1, a2,...,an)=gcd(a1, a2-a1,...,an-an-1),只需证明左式>=右式&&左式<=右式

证明完成后可以利用这一性质维护数组a的差分数组b, 那么对于a的区间修改可以转换成对b的单点修改,同时保证结果的正确性

对于查询gcd(al,...,ar),同样可以利用上面的性质转换为gcd(al, al+1-al,...,ar-ar-1),即gcd(al, bl+1, bl+2,...,br)

故而我们可以使用线段树维护区间和区间gcd,代码如下

源代码

#include <bits/stdc++.h>
#define FastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> PII;

const char sp = 32, cr = 10;
const ll inf = 0x3f3f3f3f;
const ll N = 5e5 + 5, M = 1e5;

struct node {
    ll l, r, g, s;
};
node tr[4 * N];
ll a[N], n, m;

ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}
void pushup(node& u, node& l, node& r) {
    u.g = gcd(l.g, r.g);
    u.s = l.s + r.s;
}
void pushup(ll u) {
    pushup(tr[u], tr[2 * u], tr[2 * u + 1]);
}
void build(ll u, ll l, ll r) {
    if (l == r) tr[u] = { l,r,a[l] - a[l - 1],a[l] - a[l - 1] };
    else {
        tr[u] = { l,r };
        ll mid = (l + r) / 2;
        build(2 * u, l, mid), build(2 * u + 1, mid + 1, r);
        pushup(u);
    }
}
void modify(ll u, ll p, ll v) {
    if (tr[u].l == p && tr[u].r == p) tr[u].g += v, tr[u].s += v;
    else {
        ll mid = (tr[u].l + tr[u].r) / 2;
        if (p > mid) modify(2 * u + 1, p, v);
        else modify(2 * u, p, 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) / 2;
        if (l <= mid && r > mid) {
            node nl = query(2 * u, l, r);
            node nr = query(2 * u + 1, l, r);
            node res;
            pushup(res, nl, nr);
            return res;
        }
        else if (l <= mid) return query(2 * u, l, r);
        else if (r > mid) return query(2 * u + 1, l, r);
    }
}
int main() {
    FastIO;
    cin >> n >> m;
    for (ll i = 1;i <= n;++i) cin >> a[i];
    build(1, 1, n);
    char f; ll l, r, d;
    for (ll i = 0;i < m;++i) {
        cin >> f >> l >> r;
        if (f == 'Q') {
            node nl = query(1, 1, l);       //求a[l]
            node nr = { 0,0,0,0 };
            if (r + 1 <= n) nr = query(1, l + 1, r);
            cout << abs(gcd(nl.s, nr.g)) << cr;
        }
        else {
            cin >> d;
            modify(1, l, d);
            if (r + 1 <= n)
                modify(1, r + 1, -d);
        }
    }

    return 0;
}

 

登录后才能查看或发表评论, 立即 登录
点击右上角即可分享
微信分享提示