小阳的贝壳
题目描述
小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为 \(col_i\) 。现在小阳有 3 种操作:
1 l r x:给 [l,r] 区间里所有贝壳的颜色值加上 x 。
2 l r:询问 [l,r] 区间里所有相邻贝壳 颜色值的差(取绝对值) 的最大值(若 l =r 输出 0)。
3 l r :询问 [l,r] 区间里所有贝壳颜色值的最大公约数。
输入描述:
第一行输入两个正整数 n,m,分别表示贝壳个数和操作个数。
第二行输入 n 个数 \(col_i\) ,表示每个贝壳的初始颜色。
第三到第 m + 2 行,每行第一个数为 opt,表示操作编号。接下来的输入的变量与操作编号对应。
输出描述:
共 m 行,对于每个询问(操作 2 和操作 3)输出对应的结果。
示例1
输入
5 6
2 2 3 3 3
1 2 3 3
2 2 4
3 3 5
1 1 4 2
3 2 3
2 3 5
输出
3
3
1
3
备注:
\(1 \leq n,m \leq 10^5,1 \leq col_i,x \leq 10^3,1 \leq opt \leq 3,1 \leq l \leq r \leq n\)
\(gcd(a,b)=gcd(a,b-a)\)
\(gcd(a,b,c)=gcd(a,b-a,c-b)\)
\(gcd(a_l,a_{l+1},\dots,a_r)=gcd(a_l,a_{l+1}-a_l,\dots,a_r-a_{r-1})\)
若有差分数组,则有
\(gcd(a_l,a_{l+1},\dots,a_r)=gcd(\sum_0^l d_i,gcd(d_{l+1},\dots,d_r))\)
对于op==3,只需维护差分数组区间和以及差分数组区间gcd
对于op ==2,维护差分区间最值即可
注意,op=2 [l ,r] 对于差分数组d是[l+1,r]....
代码:
#include<bits/stdc++.h>
using namespace std;
#define lson i<<1
#define rson i<<1|1
const int MAXN=1e5;
int maxx[(MAXN<<2)+5],minx[(MAXN<<2)+5],sum[(MAXN<<2)+5],g[(MAXN<<2)+5];
int n,m,data[MAXN];
inline int gcd(int a,int b){return!b?a:gcd(b, a % b);}
inline int get_gcd(int x,int y,int i=1,int l=1,int r=n){
if(x>y)return 0;
if(x<=l&&r<=y)return g[i];
int mid=(r+l)>>1;
int res=0;
if(x<=mid)res=gcd(get_gcd(x,y,lson,l,mid),res);
if(y>mid) res=gcd(get_gcd(x,y,rson,mid+1,r),res);
return res;
}
inline int get_sum(int x,int y,int i=1,int l=1,int r=n){
if(x>y)return 0;
if(x<=l&&r<=y)return sum[i];
int mid=(r+l)>>1,res=0;
if(x<=mid)res+=get_sum(x,y,lson,l,mid);
if(y>mid)res+=get_sum(x,y,rson,mid+1,r);
return res;
}
inline int get_max(int x,int y,int i=1,int l=1,int r=n){
if(x>y)return 0;
if(x<=l&&r<=y)return maxx[i];
int mid=(r+l)>>1,res=-0x7fffffff;
if(x<=mid)res=max(res,get_max(x,y,lson,l,mid));
if(y>mid)res=max(res,get_max(x,y,rson,mid+1,r));
return res;
}
inline int get_min(int x,int y,int i=1,int l=1,int r=n){
if(x>y)return 0;
if(x<=l&&r<=y)return minx[i];
int mid=(r+l)>>1,res=0x7fffffff;
if(x<=mid)res=min(res,get_min(x,y,lson,l,mid));
if(y>mid)res=min(res,get_min(x,y,rson,mid+1,r));
return res;
}
inline void up(int i){
g[i]=gcd(g[lson],g[rson]);
sum[i]=sum[lson]+sum[rson];
maxx[i]=max(maxx[lson],maxx[rson]);
minx[i]=min(minx[lson],minx[rson]);
}
inline void build(int i=1,int l=1,int r=n){
if(l==r){
sum[i]=data[l]-data[l-1];
maxx[i]=minx[i]=sum[i];
g[i]=sum[i];
return;
}
int mid=(r+l)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
up(i);
}
inline void change(int x,int val,int i=1,int l=1,int r=n){
if(l==r){
sum[i]+=val;
maxx[i]+=val;
minx[i]+=val;
g[i]+=val;
return;
}
int mid=(r+l)>>1;
if(x<=mid)change(x,val,lson,l,mid);
else change(x,val,rson,mid+1,r);
up(i);
}
void add(int x,int y,int val,int l=1,int r=n){
if(x>y)return;
change(x,val);
if(y<n)change(y+1,-val);
}
int main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;++i)cin>>data[i];
build();
int op,x,y,k;
while(m--) {
cin>>op>>x>>y;
if(op==1) {cin>>k;add(x,y,k);}
else if(op==2)cout<<max(abs(get_max(x+1,y)),abs(get_min(x+1,y)))<<endl;
else cout<<gcd(abs(get_sum(1,x)),abs(get_gcd(x+1,y)))<<endl;
}
return 0;
}