线段树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;
}