线段树1:

首先,我们知道gcd(a,b)=gcd(b-a)这样一个性质,因此我们把数组转化成为差分数组,
然后,在区间加的操作时,我们只需就行单点修改a[l],a[r+1]即可。
那么我们为什么这样做呢?
我们首先来感性的理解一下
考虑两个数组
a 1 2 3 4 5 6 7 8 9 10 11
b 1 2 3 4 5 6 7 8 9 10 11
其中a为原数组,b为我们进行区间操作的数组。
我们需要使得区间操作只影响到其对应的区间。
假如我们修改了区间 (4,7)+1
那么修改后为
a 原1 2 3 4 5 6 7 8 9 10 11
a 改1 2 3 5 6 7 8 8 9 10 11
b 改1 2 3 5 5 6 7 7 9 10 11
此时假如我们在进行查询操作时候我们去查询sum(1,l)
这样就可以使得我们的之前进行的单点操作只影响到
我们修改的区间
例如我们去查询区间(1,4) 区间s(2,7)区间(8,9)时候;
sum(1,4) sum(1,2)sum(1,8)
在原数组的基础上确实做到了,只有在待查询区间包含(4,7)区间内点的时候,
sum()操作才会影响到区间查询的结果。

好了,现在我们来看一下为什么这么做可以?

以下括号表示下标的意思
假设原数组为a(l),a(l+1),a(l+2),a(l+3)……a(r)
现在我们进行区间加操作把区间[l,r]全都加上v
此时我们需要求的是gcd(a(l)+v,a(l+1)+v,…….,a(r)+v )
由公式

可以转化为求
gcd( a(l)+v,,a(l+1)-a(l),………………,a(r)-a(r-1) )
而我们现在求得是
gcd( gcd(a(l)+v) , gcd(a(l+1)-a(l),…………….,a(r)-a(r-1)) )
所以说我们求得是对的。

ps:刚刚又有一位热心的同学提出了这样一个问题
假设我们把(2,4)区间都加上v,然后查询区间(3,5),这样a[5]不就变成了a[5]-a[4]-v了吗,这样怎么保证我们查询时的操作gcd( a[3]+v,a[4]-a[3],a[5]-a[4]-v ) ==gcd( a[3]+v,a[4]-a[3],a[5]-a[4]) ?
证明见下图:

CODE:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define MID int m = (l+r)/2
#define lson rt<<1
#define rson rt<<1|1
#define int long long
const int maxn = 2e5+7;
struct node
{
    int lazy,v,sum;
} tree[maxn<<2];
int data[maxn];
void push_up(int rt)
{
    tree[rt].v = __gcd(abs(tree[lson].v),abs(tree[rson].v));
    tree[rt].sum = tree[lson].sum+tree[rson].sum;
}
void build(int rt,int l,int r)
{
    if(l>r)return;
    if(l==r)
    {
        tree[rt].v =data[l];
        tree[rt].sum =data[l];
        return;
    }
    MID;
    build(lson,l,m);
    build(rson,m+1,r);
    push_up(rt);
}
void update(int rt,int l,int r,int pos,int v)
{
    //if(ql>r||qr<l)return;
    //if(l>r)return ;
    if(pos>r||pos<l)return;
    if(l==r)
    {
        tree[rt].sum+=v;
        tree[rt].v+=v;
        return;
    }
    MID;
    update(lson,l,m,pos,v);
    update(rson,m+1,r,pos,v);
    push_up(rt);
}
int query1(int rt,int l,int r,int ql,int qr)
{

    if(l>r)return 0;
    if(ql>r||qr<l)return 0;
    if(ql<=l&&r<=qr)
    {
        return tree[rt].sum;
    }
    MID;
    int h1 =  query1(lson,l,m,ql,qr);
    int h2  = query1(rson,m+1,r,ql,qr);


    // push_up(rt);
    return h1+h2;
}
int query2(int rt,int l,int r,int ql,int qr)
{
    if(ql>r||qr<l)return 0;
    if(l>r)return 0;
    if(ql<=l&&r<=qr)
    {
        return tree[rt].v;
    }
    MID;
    int h1 = query2(lson,l,m,ql,qr);
    int h2 = query2(rson,m+1,r,ql,qr);
    return __gcd(h1,h2);
    // push_up(rt);
    //return
}
signed main()
{
    int n;
    scanf("%lld",&n);

    int q;
    scanf("%lld",&q);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&data[i]);
    }
    for(int i=n; i>1; i--)
    {
        data[i] -= data[i-1];
    }
    build(1,1,n);
    while(q--)
    {
        int op,ql,qr,v;
        scanf("%lld%lld%lld",&op,&ql,&qr);
        if(ql>qr)swap(ql,qr);
        if(op==1)
        {
            long long ans = query1(1,1,n,1,ql);
            long long ans2 = query2(1,1,n,ql+1,qr);
            // cout<<"**"<<ans<<" "<<ans2<<endl;
            ans = __gcd(ans,ans2);
            printf("%lld\n",abs(ans));

        }
        else
        {
            scanf("%lld",&v);
            update(1,1,n,ql,v);
            if(qr<n)update(1,1,n,qr+1,-v);

        }
    }
    return 0;
}