题目链接:https://ac.nowcoder.com/acm/contest/949/H
题目大意:
题解:模板题,用线段树维护区间gcd很容易维护,维护区间带修改的gcd需要用到gcd的性质(看似简单但我不会)。设有区间有
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d 数字,则
g
c
d
(
a
,
b
,
c
,
d
)
=
g
c
d
(
a
,
b
−
a
,
c
−
b
,
d
−
c
)
gcd(a,b,c,d) = gcd(a,b - a,c - b, d - c)
gcd(a,b,c,d)=gcd(a,b−a,c−b,d−c),容易发现除了第一个数字,后面都是差分的形式(知识盲区)。再有区间
g
c
d
(
a
,
b
,
c
,
d
)
=
g
c
d
(
a
,
g
c
d
(
b
,
c
,
d
)
)
gcd(a,b,c,d) = gcd(a,gcd(b,c,d))
gcd(a,b,c,d)=gcd(a,gcd(b,c,d)), 即gcd具有区间可加性,可以用线段树维护合并gcd,因此这题用线段树维护
a
a
a数组的差分数组的区间gcd即可,区间修改对于差分数组而言也是端点修改,所有的修改都是单点修改。注意查询的时候左端点不是差分形式,要求前缀和,可以用线段树也维护区间和快速求前缀和。
#include<bits/stdc++.h>
using namespace std;
#define lson rt << 1,l,mid
#define rson rt << 1 | 1,mid + 1,r
const int maxn = 1e5 + 10;
int n,m,a[maxn];
int g[maxn << 2],val[maxn << 2],sum[maxn << 2];
int gcd(int a,int b) {
return !b ? a : gcd(b,a % b);
}
void update(int p,int v,int rt,int l,int r) {
if(l == r) {
sum[rt] = v;
val[rt] = max(v,-v);
g[rt] = val[rt];
return;
}
int mid = l + r >> 1;
if(p > mid) update(p,v,rson);
else update(p,v,lson);
g[rt] = gcd(g[rt << 1],g[rt << 1 | 1]);
val[rt] = max(val[rt << 1],val[rt << 1 | 1]);
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
int query(int L,int R,int type,int rt,int l,int r) {
if(L <= l && r <= R) {
if(type == 1) return val[rt];
else if(type == 2) return g[rt];
else if(type == 3) return sum[rt];
}
int mid = l + r >> 1;
int mx = 0;
if(type == 1) {
if(mid >= L) mx = max(mx,query(L,R,type,lson));
if(mid + 1 <= R) mx = max(mx,query(L,R,type,rson));
}
else if(type == 2) {
if(mid >= L) mx = gcd(mx,query(L,R,type,lson));
if(mid + 1 <= R) mx = gcd(mx,query(L,R,type,rson));
}
else if(type == 3) {
if(mid >= L) mx += query(L,R,type,lson);
if(mid + 1 <= R) mx += query(L,R,type,rson);
}
return mx;
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
for(int i = n; i >= 1; i--) {
a[i] -= a[i - 1];
update(i,a[i],1,1,n);
}
for(int i = 1; i <= m; i++) {
int type,x,y,v;
scanf("%d%d%d",&type,&x,&y);
if(type == 1) {
scanf("%d",&v);
a[x] += v;
a[y + 1] -= v;
update(x,a[x],1,1,n);
if(y + 1 <= n)
update(y + 1,a[y + 1],1,1,n);
}
else if(type == 2) {
if(x == y) printf("0\n");
else
printf("%d\n",query(x + 1,y,1,1,1,n));
}
else {
int p = query(1,x,3,1,1,n);
if(x < y) p = gcd(p,query(x + 1,y,2,1,1,n));
printf("%d\n",p);
}
}
return 0;
}