chenfy27的刷题记录

导航

acwing246 区间最大公约数

给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

  • C l r d,表示把A[l],A[l+1],...A[r]都加上d。
  • Q l r,表示查询A[l],A[l+1],...A[r]的最大公约数。

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

分析:利用差分数组,将区间修改转换成两次单点修改。再用差分数组构造出原数组区间的最大公约数,例如gcd(a,b,c) = gcd(a,b-a,c-d) = gcd(a, gcd(b-a,c-d)),因此可以拆成两部分计算,左边是前缀和,右边是区间gcd,二者都可以用线段树来维护。

#include <bits/stdc++.h>
using i64 = long long;

i64 mygcd(i64 x, i64 y) {
    return y ? mygcd(y, x%y) : x;
}

// SegmentTree模板...

struct Info {
    i64 gcd, sum;
    Info(i64 v=0):gcd(v),sum(v) {}
    friend Info operator+(const Info &a, const Info &b) {
        Info ans;
        ans.gcd = mygcd(a.gcd, b.gcd);
        ans.sum = a.sum + b.sum;
        return ans;
    }
};

void solve() {
    int N, M;
    std::cin >> N >> M;
    std::vector<i64> A(N), B(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }
    std::adjacent_difference(A.begin(), A.end(), B.begin());
    SegmentTree<Info> seg(B);
    for (int i = 0; i < M; i++) {
        std::string op;
        i64 l, r, d;
        std::cin >> op >> l >> r;
        l--, r--;
        if (op == "C") {
            std::cin >> d;
            seg.modify(l, Info(d));
            if (r + 1 < N) {
                seg.modify(r+1, Info(-d));
            }
        } else if (op == "Q") {
            i64 gcd1 = seg.rangeQuery(0, l+1).sum;
            i64 gcd2 = seg.rangeQuery(l+1, r+1).gcd;
            std::cout << std::abs(mygcd(gcd1, gcd2)) << "\n";
        }
    }
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

posted on 2024-06-18 23:31  chenfy27  阅读(30)  评论(0)    收藏  举报