给定一个长度为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 N≤500000,M≤100000 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的性质就是 g c d ( a , b ) = g c d ( a , b − a ) gcd(a,b)=gcd(a,b-a) gcd(a,b)=gcd(a,b−a)
再写清楚一点就是 g c d ( a 1 , a 2 , a 3 . . . . a n ) = g c d ( a 1 , a 2 − a 1 , a 3 − a 2 . . . a n − a n − 1 ) gcd(a_1,a_2,a_3....a_n)=gcd(a_1,a_2-a_1,a_3-a_2...a_n-a_{n-1}) gcd(a1,a2,a3....an)=gcd(a1,a2−a1,a3−a2...an−an−1)
所以我们对于gcd的性质变成一个差分数组。对于差分数组我们的区间修改也就变成了单点修改。
对于我们区间求gcd也就变成了 g c d ( a l , g c d ( a l + 1 , a r ) ) gcd(a_l,gcd(a_{l+1},a_r)) gcd(al,gcd(al+1,ar))对于 a l a_l al就是我们1-l的前缀和,对于后面一坨就是后面一个区间的gcd。所以答案也就出来了。
#include
#define int long long
using namespace std;
#define lson u<<1
#define rson u<<1|1
const int N=5e5+7;
int n,m,a[N];
struct Node{
int l,r;
long long sum,gcd;
}tr[N<<2];
long long __gcd(long long a, long long b)
{
return b ? __gcd(b, a % b) : a;
}
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[lson],tr[rson]);
}
void build(int u,int l,int r)
{
if(l==r){
long long b=a[l]-a[l-1];
tr[u]={l,r,b,b};
return;
}
int mid=l+r>>1;
tr[u]={l,r};
build(lson,l,mid);
build(rson,mid+1,r);
pushup(u);
}
Node query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u];
}
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(lson,l,r);
else if(l>mid) return query(rson,l,r);
else{
auto left=query(lson,l,r);
auto right=query(rson,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
void modify(int u,int x,int c)
{
if(tr[u].l==x&&tr[u].r==x){
long long b=tr[u].sum+c;
tr[u]={x,x,b,b};
return ;
}
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid) modify(lson,x,c);
else if(x>mid) modify(rson,x,c);
pushup(u);
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",a+i);
build(1,1,n);
for(int i=1;i<=m;i++){
char op[3];
scanf("%s",op);
if(*op=='Q'){
int l,r; scanf("%lld%lld",&l,&r);
auto left=query(1,1,l);
auto right=query(1,l+1,r);
printf("%lld\n",abs(__gcd(left.sum,right.gcd)));
}else{
int l,r,c;
scanf("%lld%lld%lld",&l,&r,&c);
modify(1,l,c);
if(r+1<=n) modify(1,r+1,-c);
}
}
return 0;
}