水题*3
我们处理出差分数组,注意到gcd(a,b)=gcd(b,a-b),满足差分的样子,因此可以用线段树维护差分数组,区间加相当于单点修改,需注意的是询问[l,r]的第一个点需要前缀和统计
#include<bits/stdc++.h>
const int N=200005;
using namespace std;
template<class T>
inline void read(T &x)
{
x=0;
static char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
}
struct Tree
{
int l,r,gcd,sum,f;
}tree[4*N];
int n,val[N],diff[N];
void pushup(int now)
{
tree[now].gcd=__gcd(tree[2*now].gcd,tree[2*now+1].gcd);
tree[now].sum=tree[2*now].sum+tree[2*now+1].sum;
}
void build(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r;
if(l==r)
{
tree[now].gcd=tree[now].sum=diff[l];
return;
}
int m=(l+r)>>1;
build(2*now,l,m);
build(2*now+1,m+1,r);
pushup(now);
}
inline void update(int now,int k,int v)
{
if(tree[now].l==k&&tree[now].r==k)
{
tree[now].gcd+=v;
tree[now].sum+=v;
return;
}
int m=(tree[now].l+tree[now].r)>>1;
if(k<=m) update(2*now,k,v);
else update(2*now+1,k,v);
pushup(now);
}
inline int query1(int now,int l,int r)
{
if(l<=tree[now].l&&tree[now].r<=r) return tree[now].sum;
int m=(tree[now].l+tree[now].r)>>1;
int ans=0;
if(l<=m) ans+=query1(2*now,l,r);
if(r>m) ans+=query1(2*now+1,l,r);
return ans;
}
inline int query2(int now,int l,int r)
{
if(l<=tree[now].l&&tree[now].r<=r) return tree[now].gcd;
int m=(tree[now].l+tree[now].r)>>1;
int ans=0;
if(l<=m) ans=__gcd(ans,query2(2*now,l,r));
if(r>m) ans=__gcd(ans,query2(2*now+1,l,r));
return ans;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) read(val[i]);
for(int i=1;i<=n;i++) diff[i]=val[i]-val[i-1];
build(1,1,n);
int T;
cin>>T;
while(T--)
{
int opt,l,r,v; read(opt);
if(opt==0)
{
read(l); read(r);
int head=query1(1,1,l);
int back=query2(1,l+1,r);
cout<<abs(__gcd(head,back))<<'\n';
}
else
{
read(l); read(r); read(v);
update(1,l,v);
if(r+1<=n) update(1,r+1,-v);
}
}
return 0;
}