- 差分
- $\gcd$
证明:$\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})$.
为方便描述 令 $c_1=a_1,c_i=a_i-a_{i-1},i>1$.
设其最大公约数为 $d$ , 则 $d|a_1,d|a_2,…, –> d|(a_2-a_1)…$
左边$=d$;
右边$=d \times \gcd(c_1/d,c_2/d,…)$
引理:$\gcd(c_1/d,c_2/d,…)=1$
反证法:若 $\gcd(c_1/d,c_2/d,…)=k,k>1$.
- 则 $a_1/d=c_1/d=x \times k$
- $c_2/d=(a_2-a_1)/d=y \times k$
- $a_2/d=(a_1+c_2)/d=x \times k + y \times k=(x+y) \times k$,$k|a_2$
- …
- 同理得 $k|(a_i/d),i \in [1,n]$
则 $\gcd(a_1,a_2,a_3,…,a_n)=d \times k$.
与题设不符,舍去。
所以 $\gcd(c_1/d,c_2/d,…)=1$。
右边$=d \times \gcd(c_1/d,c_2/d,…)= d = $ 左边。
即证。
Code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=5e5+5;
LL a[N],c[N];
int n,m;
LL gcd(LL a,LL b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
#define lc (now<<1)
#define rc (now<<1|1)
LL sum[4*N],d[4*N];
void Update(int now,int pos,LL key,int l,int r)
{
if(l==r&&l==pos) {
sum[now]+=key;
d[now]+=key;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) Update(lc,pos,key,l,mid);
else Update(rc,pos,key,mid+1,r);
sum[now]=sum[lc]+sum[rc];
d[now]=gcd(d[lc],d[rc]);
}
LL QuerySum(int now,int pos,int l,int r)
{
if(r<=pos) return sum[now];
int mid=(l+r)>>1;
LL res=QuerySum(lc,pos,l,mid);
if(pos>=mid+1) res+=QuerySum(rc,pos,mid+1,r);
return res;
}
LL QueryGcd(int now,int x,int y,int l,int r)
{
if(x<=l&&r<=y) return d[now];
int mid=(l+r)>>1;
LL res=0;
if(x<=mid) res=gcd(res,QueryGcd(lc,x,y,l,mid));
if(y>=mid+1) res=gcd(res,QueryGcd(rc,x,y,mid+1,r));
return res;
}
int main()
{
int i;
int x,y;
LL z;
char opt;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) {
scanf("%lld",&a[i]);
c[i]=a[i]-a[i-1];
Update(1,i,c[i],1,n);
}
while(m--) {
for(opt=getchar();opt!='C'&&opt!='Q';opt=getchar());
scanf("%d%d",&x,&y);
if(opt=='Q') printf("%lld\n",abs(gcd(QueryGcd(1,x+1,y,1,n),QuerySum(1,x,1,n))));
else {
scanf("%lld",&z);
Update(1,x,z,1,n);
if(y+1<=n) Update(1,y+1,-z,1,n);
}
}
return 0;
}