题解
$\color{red}{题解传送门}$
题目
题目传送门
题解
- $\gcd(a,b)=\gcd(a, b-a)$
- $\gcd(a,b,c) = \gcd(a,b-a, c-b)$
- $\gcd(a_1,a_2,\cdots,a_n) = \gcd(a_1, a_2-a_1, a_3-a_2,\cdots,a_n-a_{n-1})$
- 知道了这个性质我们可以开一个$B[\ \ ]$数组,表示原序列的差分序列,用线段数维护$B$的区间最大公约数
- 对于询问“Q l r”等于求出$\gcd(a[l], query(1,l+r, r))$
- 对于询问”C l r d”等于$B[l]$加上$d$,$B[r+1]$减去$d$,只需两次线段数的单点修改即可(线段树单点修改模板),对于原序列中$A$的值,我们可以用一个“区间修改+单点查询”的树状数组来维护(树状数组区间修改+单点查询模板)
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 100;
typedef long long LL;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
LL n, m;
LL a[maxn], b[maxn], c[maxn]; // 原数组,差分数组,增量数组(树状数组)
struct node {
LL l, r;
LL dat;
} t[maxn * 4];
inline LL gcd(LL x, LL y) { return y ? gcd(y, x % y) : x; }
inline void build(LL p, LL l, LL r) {
t[p].l = l, t[p].r = r;
if (l == r) { t[p].dat = b[l]; return ; }
LL mid = (l + r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid + 1, r);
t[p].dat = gcd(t[p<<1].dat, t[p<<1|1].dat);
}
inline void change(LL p, LL x, LL val) {
if (t[p].l == t[p].r) { t[p].dat += val; return ; }
LL mid = (t[p].l + t[p].r)>>1;
if (x <= mid) change(p<<1, x, val);
else change(p<<1|1, x, val);
t[p].dat = gcd(t[p<<1].dat, t[p<<1|1].dat);
}
inline LL query(LL p, LL l, LL r) {
if (l <= t[p].l && r >= t[p].r) return t[p].dat;
LL mid = (t[p].l + t[p].r)>>1;
LL val = 0;
if (l <= mid) val = gcd(val, query(p<<1, l, r));
if (r > mid) val = gcd(val, query(p<<1|1, l, r));
return abs(val);
}
inline LL lowbit(LL x) { return x & -x; }
inline void add(LL x, LL val) {
for (; x <= n; x += lowbit(x))
c[x] += val;
}
inline LL ask(LL x) {
LL ans = 0;
for (; x; x -= lowbit(x))
ans += c[x];
return ans;
}
int main() {
read(n), read(m);
for (LL i = 1; i <= n; ++i) {
read(a[i]);
b[i] = a[i] - a[i-1];
}
build(1, 1, n);
for (LL i = 1; i <= m; ++i) {
char opt[2]; LL l, r, val;
scanf("%s", opt);
if (opt[0] == 'Q') {
read(l), read(r);
LL now = a[l] + ask(l);
printf("%lld\n", gcd(now, query(1, l+1, r)));
} else {
read(l), read(r), read(val);
add(l, val);
add(r + 1, -val);
change(1, l, val);
if (r < n) change(1, r + 1, -val);
}
}
return 0;
}