AcWing 246 区间最大公约数 (线段树)
题目链接:https://www.acwing.com/problem/content/description/247/
更相减损术:\(gcd(a,b) = gcd(a,a - b)\)
可以扩展到 \(n\) 个数,\(gcd(a,b,c) = gcd(a,b-a,c-b)\)
于是可以用线段树维护\(a\)的差分数组\(b\),查询时的答案即为\(gcd(a[L],query(l+1,r)\)
细节:
- \(gcd(a,b) = gcd(a,-b)\), 对结果取负
- \(gcd\)中\(a,b\)为\(0\)没有关系
- \(long long\)
- \(r+1\)可能越界,\(n+1\) 即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 500010;
int n, m;
ll a[maxn], b[maxn], c[maxn];
char s[10];
struct SEG{
ll gc;
}t[maxn << 2];
ll gcd(ll x, ll y){ return y? gcd(y, x % y) : x; }
void add(ll x, ll y){
for(; x <=n ; x += x & (-x))
c[x] += y;
}
ll ask(ll x){
ll sum = 0;
for(; x ; x -= x & (-x))
sum += c[x];
return sum;
}
void pushup(int i){
t[i].gc = gcd(t[i << 1].gc, t[i << 1 | 1].gc);
}
void build(int i, int l, int r){
if(l == r){
t[i].gc = b[l];
return;
}
int mid = (l + r) >> 1;
build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r);
pushup(i);
}
void modify(int i, int l, int r, int p, ll k){
if(l == r){
t[i].gc += k;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) modify(i << 1, l, mid , p, k);
else modify(i << 1 | 1, mid + 1, r, p ,k);
pushup(i);
}
ll query(int i, int l, int r, int x, int y){
if(x > y) return 0;
if(x <= l && r <= y){
return t[i].gc;
}
int mid = (l + r) >> 1;
if(y <= mid) return query(i << 1, l, mid, x, y);
else if(x > mid) return query(i << 1 | 1, mid + 1 , r, x, y);
else return gcd(query(i << 1, l, mid, x, y), query(i << 1 | 1, mid + 1 , r, x, y));
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i){
scanf("%lld",&a[i]);
b[i] = a[i] - a[i - 1];
add(i, b[i]);
}
b[++n] = -b[n-1];
build(1, 1, n);
int x, y; ll d;
for(int i = 1; i <= m; ++i){
scanf("%s%d%d", s, &x, &y);
if(s[0] == 'Q'){
ll A = ask(x);
ll B = query(1, 1, n, x + 1, y);
printf("%lld\n", abs(gcd(A, B)));
} else{
scanf("%lld", &d);
modify(1, 1, n, x, d);
modify(1, 1, n, y + 1, -d);
add(x, d); add(y + 1, -d);
}
}
return 0;
}