https://www.acwing.com/problem/content/247/
时/空限制: 1s / 64MB
给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行表示M条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
N≤500000,M≤100000N≤500000,M≤100000
输入样例:
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
输出样例:
1
2
4
思路:根据最大公约数的分配律,gcd(a,b,c) = gcd(a,b-a,c-b);
那么对于数列来说,gcd(a1, a2, a3, a4.....) = gcd(a1, a2-a1, a3-a2, a4-a3...)
那么当我们计算区间最大公约数的时候,实际上是在计算,gcd(a1, gcd(a2-a1, a3-a2.....al-al-1));
那么我们需要维护一个差分值和一个gcd值。
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 5e5 + 10;
ll a[N],b[N];
int n,m;
struct node{
int l, r;
ll sum, gcd;
}tr[N*4];
void pushup(node &u, node &l, node &r)
{
u.sum = l.sum + r.sum;
u.gcd = __gcd(l.gcd, r.gcd);
}
void pushup(int u)
{
pushup(tr[u], tr[u<<1], tr[u<<1|1]);
}
void build(int u, int l, int r)
{
if(l == r) tr[u] = {l, l, b[l], b[l]};
else
{
tr[u] = {l, r};
int mid = l + r >> 1;
build(u<<1, l, mid);
build(u<<1|1, mid+1, r);
pushup(u);
}
}
void modify(int u, int x, ll v)
{
if(tr[u].l == x && tr[u].r == x)
{
tr[u].sum += v;
tr[u].gcd = tr[u].sum;
}
else
{
int mid = (tr[u].l + tr[u].r) >> 1;
if(x <= mid) modify(u<<1, x, v);
else if(x > mid) modify(u<<1|1, x, v);
pushup(u);
}
}
ll query_sum(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
else
{
int mid = (tr[u].l + tr[u].r) >> 1;
if(r <= mid) return query_sum(u<<1, l ,r);
else if(l > mid) return query_sum(u<<1|1, l, r);
else return query_sum(u<<1, l, r) + query_sum(u<<1|1, l, r);
}
}
ll query_gcd(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].gcd;
int mid = (tr[u].l + tr[u].r) >> 1;
if(r <= mid) return query_gcd(u<<1, l, r);
else if(l > mid) return query_gcd(u<<1|1, l, r);
else return __gcd(query_gcd(u<<1, l, r), query_gcd(u<<1|1, l, r));
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++) scanf("%lld", &a[i]), b[i] = a[i] - a[i-1];
char op[4];
int l,r;
ll v;
build(1, 1, n);
while(m--)
{
scanf("%s%d%d",op,&l,&r);
if(*op == 'C')
{
scanf("%lld",&v);
modify(1, l, v);
if(r + 1 <= n) modify(1, r+1, -v);
}
else
{
ll x = query_sum(1, 1, l);
ll y = query_gcd(1, l+1, r);
cout<<abs(__gcd(x,y))<<endl;
}
}
return 0;
}