区间GCD的修改和查找
链接
众所周知,
gcd
(
a
,
b
)
=
gcd
(
b
,
a
−
b
)
\gcd(a,b)=\gcd(b,a-b)
gcd(a,b)=gcd(b,a−b),推广到
3
3
3维,就是
gcd
(
a
,
b
,
c
)
=
gcd
(
a
,
b
−
a
,
c
−
b
)
\gcd(a,b,c)=\gcd(a,b-a,c-b)
gcd(a,b,c)=gcd(a,b−a,c−b),依次类推,求下标在
[
i
,
j
]
[i,j]
[i,j]里的所有数的
gcd
\gcd
gcd即为
gcd
(
a
i
,
a
i
+
1
−
a
i
,
.
.
.
.
,
a
j
−
a
j
−
1
)
\gcd(a_i,a_{i+1}-a_i,....,a_j-a_{j-1})
gcd(ai,ai+1−ai,....,aj−aj−1),可以看到这个区间内所有数的和为
a
i
a_i
ai,所以我们可以维护两个部分,一个是
a
i
a_i
ai,另一个是
(
a
i
+
1
−
a
i
,
a
i
+
2
−
a
i
+
1
,
.
.
.
,
a
j
−
a
j
−
1
)
(a_{i+1}-a_i,a_{i+2}-a_{i+1},...,a_j-a_{j-1})
(ai+1−ai,ai+2−ai+1,...,aj−aj−1),前者用树状数组维护即可,后者用线段树维护即可。
AC代码:
#include <bits/stdc++.h>
#define sc(z) scanf("%lld", &(z))
#define IO ios::sync_with_stdio(0)
#define _f(i, a, b) for (int i = a; i < b; ++i)
#define _ff(i, a, b) for (int i = a; i <= b; ++i)
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
ll a[N], b[N], t[N<<2], c[N], n;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
void build(int node, int l, int r) {
if (l == r) {
t[node] = b[l];
return;
}
int mid = (l + r) >> 1;
build(node<<1, l, mid);
build(node<<1|1, mid + 1, r);
t[node] = gcd(t[node<<1] ,t[node<<1|1]);
}
void update(int node, int l, int r, int x, ll k) {
if (l == r && l == x) {
t[node] += k;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) update(node<<1, l, mid, x, k);
else update(node<<1|1, mid + 1, r, x, k);
t[node] = gcd(t[node<<1], t[node<<1|1]);
}
ll query(int node, int l, int r, int L, int R) {
if (l >= L && r <= R) return t[node];
int mid = (l + r) >> 1; ll res = 0;
if (L <= mid) res = gcd(res, query(node<<1, l, mid, L, R));
if (R > mid) res = gcd(res, query(node<<1|1, mid + 1, r, L, R));
return abs(res);
}
void add(int x, ll y) { for (; x <= n; x += lowbit(x)) c[x] += y; }
ll ask(int x) {
ll ans = 0;
for (; x; x -= lowbit(x)) ans += c[x];
return ans;
}
int main() {
IO;
int q; cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
b[i] = a[i] - a[i - 1];
}
build(1, 1, n);
char op;
ll l, r, d;
while (q--) {
cin >> op;
if (op == 'C') {
cin >> l >> r >> d;
update(1, 1, n, l, d);
if (r < n) update(1, 1, n, r + 1, -d);
add(l, d); add(r + 1, -d);
} else {
cin >> l >> r;
cout << gcd(a[l] + ask(l), query(1, 1, n, l + 1, r)) << endl;
}
}
return 0;
}