/*
* 将原序列转换为差分序列,区间加操作就可以转换为两个点的操作
* 同时用线段树维护差分序列的前缀和以及差分序列的gcd
*
* 对于一个原始序列i到j的分片 a(i), a(i+1), a(i+2), ....... a(j)
* 而言,其最大公约数等于序列 a(i), a(i+1)-a(i), a(i+2)-a(i-1), ..... , a(j)-a(j-1)
* 的最大公约数,因此在求区间的最大公约数时候,可以利用前缀和先算出a(i), 然后求后半部分
* 从a(i+1)-a(i)开始到a(j)-a(j-1)结束的差分序列的区间最大公约数,然后两个数值再求一次
* 最大公约数就是答案
*
*/
#include <stdio.h>
#include <algorithm>
using namespace std;
struct Data {
long long sum; // 区间总和
long long gcd; // 区间所有数的最大公约数
};
struct Node {
int start; // 区间开始位置
int end; // 区间结束位置
Data data;
}__global_nodes[500005*4] ;
class SegmentTree {
private:
Node* __nodes; // 节点数组
int __n; // 区间为0到n-1
long long __gcd(long long a, long long b) {
if (a < 0) {
a = -a;
}
if (b < 0) {
b = -b;
}
if (a > b) {
long long t = a; a = b; b = t;
}
while (a) {
long long t = b % a;
b = a;
a = t;
}
return b;
}
// 更新单个位置的数值
void __update_single(int node_idx, int pos, long long val) {
Node& node = __nodes[node_idx];
if (node.start == node.end) {
node.data.gcd += val;
node.data.sum += val;
return;
}
int mid = (node.start + node.end) >> 1;
if (pos <= mid) {
__update_single(node_idx*2+1, pos, val);
} else {
__update_single(node_idx*2+2, pos, val);
}
Data data1 = __nodes[node_idx*2 + 1].data;
Data data2 = __nodes[node_idx*2 + 2].data;
node.data.sum = data1.sum + data2.sum;
node.data.gcd = __gcd(data1.gcd, data2.gcd);
}
// 获取区间的数值的和
long long __get_sum(int node_idx, int start, int end) {
Node& node = __nodes[node_idx];
if (node.start == start && node.end == end) {
return node.data.sum;
}
int mid = (node.start + node.end) >> 1;
if (end <= mid) {
return __get_sum(node_idx*2+1, start, end);
} else if (start >= mid+1) {
return __get_sum(node_idx*2+2, start, end);
} else {
long long val1 = __get_sum(node_idx*2+1, start, mid);
long long val2 = __get_sum(node_idx*2+2, mid+1, end);
return val1 + val2;
}
}
// 获取区间的最大公约数
long long __get_gcd(int node_idx, int start, int end) {
Node& node = __nodes[node_idx];
if (node.start == start && node.end == end) {
return node.data.gcd;
}
int mid = (node.start + node.end) >> 1;
if (end <= mid) {
return __get_gcd(node_idx*2+1, start, end);
} else if (start >= mid+1) {
return __get_gcd(node_idx*2+2, start, end);
} else {
long long val1 = __get_gcd(node_idx*2+1, start, mid);
long long val2 = __get_gcd(node_idx*2+2, mid+1, end);
return __gcd(val1, val2);
}
}
// 获取区间统计信息
long long __get_val(int node_idx, int start, int end) {
if (start == end) {
return __get_sum(0, 0, start);
}
long long sum_val = __get_sum(0, 0, start);
long long gcd_val = __get_gcd(0, start+1, end);
return __gcd(sum_val, gcd_val);
}
public:
SegmentTree(int n, Node* pnodes) {
__n = n;
__nodes = pnodes;
__nodes[0] = {0, n-1, 0};
for (int i = 0; i < __n << 2; i++) {
if (__nodes[i].start == __nodes[i].end and __nodes[i].end == __n-1) {
break;
}
int mid = (__nodes[i].start + __nodes[i].end) / 2;
__nodes[i*2+1] = {__nodes[i].start, mid, 0};
__nodes[i*2+2] = {mid+1, __nodes[i].end, 0};
}
}
// 更新单个数据接口
void update_single(int pos, long long val) {
__update_single(0, pos, val);
}
// 获取区间统计数据接口
long long get_val(int start, int end) {
return __get_val(0, start, end);
}
};
int main(void) {
//freopen("/Users/grh/Programming/CLionProjects/Test/data.txt", "r", stdin);
int n, m;
long long val;
scanf("%d %d", &n, &m);
SegmentTree tree(n, __global_nodes);
long long last_val = 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &val);
tree.update_single(i, val-last_val);
last_val = val;
}
char c[2];
int start, end;
for (int i = 0; i < m; i++) {
scanf("%s", c);
if (c[0] == 'Q') {
scanf("%d %d", &start, &end);
printf("%lld\n", tree.get_val(start-1, end-1));
} else {
scanf("%d %d %lld", &start, &end, &val);
tree.update_single(start-1, val);
if (end < n) {
tree.update_single(end, -val);
}
}
}
return 0;
}