题目描述
给定一个长度为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 ≤ 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可以通过维护差分序列求解。
差分:把对区间的加减变成单点加减,不再需要lazy标记
线段树维护序列差分序列的区间gcd
在询问数组a的值时,额外用一个支持“区间增加、单点查询”的树状数组对a进行维护。
// Interval GCD
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
using ll = long long;
const int maxn = 5e5 + 10;
struct SegmentTree
{
int l, r;
ll dat; // 差分序列的区间gcd
} tree[maxn << 2];
ll a[maxn], d[maxn], c[maxn];
int n, m;
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
void pushup(int p)
{
tree[p].dat = gcd(tree