0
点赞
收藏
分享

微信扫一扫

【AcWing 246. 区间最大公约数】线段树维护区间最大公约数+数学知识+差分

回望这一段人生 2022-03-16 阅读 42

题目链接

题意:

给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:
C l r d,表示把 A[l],A[l+1],…,A[r] 都加上 d。
Q l r,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
对于每个询问,输出一个整数表示答案。

分析:

一看到区间加法就会想到线段树lazy标记,但是这个lazy标记对sum是有用的,对gcd可就没有用了,假如说一段区间的最大公约数是x,那么给这段区间所有的数都加上1,那么这个区间的最大公约数还是x吗?那显然不是的,那么咱们现在可以换个思考方式了,如果是单点修改呢,单点修改是可以做到log时间维护gcd的,假如咱们需要求gcd(a[l],a[l+1],…,a[r-1],a[r]),那么有个结论,就是这个最大公约数也等于gcd(a[l],a[l+1]-a[l],…,a[r]-a[r-1]),那么这是为什么呢?咱们可以用y总教的方法来证明一下,证明前者大于等于后者,后者大于等于前者,那么前者就等于后者了,假如gcd(a[l],a[l+1],…,a[r-1],a[r]) = t,那么,a[l+1]-a[l]也是t的倍数,a[l+2]-a[l+1]也是t的倍数,所以后者大于等于前者,假如后者等于t,那么a[l]就是t的倍数,因为a[l+1]-a[l]是t的倍数,a[l]是t的倍数,所以说a[l+1]也是t的倍数,所以前者大于等于后者,那么咱们只需要求gcd(a[l],a[l+1]-a[l],a[l+2]-a[l+1],…,a[r]-a[r-1])即可,那么a[l]就是前l个数的差分的和,后面r-l个数的gcd可以通过线段树维护得出,下面请看代码:

#include<bits/stdc++.h>
#define ll (k<<1)
#define rr (k<<1|1)
#define Mid (tr[k].l + tr[k].r >> 1)
#define Len (tr[k].r - tr[k].l + 1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int mod = 1e9+7;
const int N = 500010;
LL n,m,a[N],b[N];
struct node{
int l,r;
LL gcd,sum;
};
node tr[N<<2];
void pu(node &a,node &b,node &c){
a.gcd = __gcd(b.gcd,c.gcd);
a.sum = b.sum + c.sum;
}
void build(int k,int l,int r){
tr[k] = {l,r,0,0};
if(l == r){
tr[k].gcd = tr[k].sum = a[l];
return;
}
build(ll,l,Mid);build(rr,Mid+1,r);
pu(tr[k],tr[ll],tr[rr]);
}
void change(int k,int pos,LL val){
if(pos > tr[k].r || pos < tr[k].l) return;
if(tr[k].l == tr[k].r && tr[k].l == pos){
tr[k].gcd += val;
tr[k].sum += val;
return ;
}
if(pos <= Mid) change(ll,pos,val);
else change(rr,pos,val);
pu(tr[k],tr[ll],tr[rr]);
}
node query(int k,int l,int r){
if(tr[k].l >= l && tr[k].r <= r) return tr[k];
if(r <= Mid){
return query(ll,l,r);
}
else if(l > Mid){
return query(rr,l,r);
}
else {
node left = query(ll,l,r),right = query(rr,l,r);
node ans;
pu(ans,left,right);
return ans;
}
}
int main(){
scanf("%lld%lld",
for(int i=1;i<=n;i++){
scanf("%lld",
a[i] = b[i] - b[i-1];
}
build(1,1,n);
while(m--){
char op[2];
scanf("%s",op);
if(op[0] == 'Q'){
int l,r;
scanf("%d%d",
node t = query(1,l,r);
// cout<<query(1,1,r).sum<<" "<<query(1,l+1,r).gcd<<endl;
// continue;
node a = query(1,1,l),b = {0,0,0,0};
if(l + 1 <= r)
b = query(1,l+1,r);
printf("%lld
"
,abs(__gcd(a.sum,b.gcd)));
}
else{
int l,r;
LL x;
scanf("%d%d%lld",
change(1,l,x);
if(r + 1 <= n)
change(1,r+1,-x);
}
}
// system("pause");
return 0;
}
举报

相关推荐

0 条评论