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;
}
浙公网安备 33010602011771号