链接:https://ac.nowcoder.com/acm/contest/949/H
来源:牛客网
题目描述
小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为 colicoli 。现在小阳有 3 种操作:
1 l r x:给 [l,r][l,r] 区间里所有贝壳的颜色值加上 xx 。
2 l r:询问 [l,r][l,r] 区间里所有相邻贝壳 颜色值的差(取绝对值) 的最大值(若 l=rl=r 输出 0)。
3 l r :询问 [l,r][l,r] 区间里所有贝壳颜色值的最大公约数。
输入描述:
第一行输入两个正整数 n,mn,m,分别表示贝壳个数和操作个数。 第二行输入 nn 个数 colicoli,表示每个贝壳的初始颜色。 第三到第 m+2m+2 行,每行第一个数为 optopt,表示操作编号。接下来的输入的变量与操作编号对应。
输出描述:
共 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≤n,m≤105,1≤coli,x≤103,1≤opt≤3,1≤l≤r≤n
思路:这题关键是维护一个区间的gcd如果知道gcd(a,b)=gcd(a,b-a); gcd(a,b,c)=gcd(a,gcd(b,c))=gcd(a,gcd(b,c-b))=gcd(gcd(a,b-a),c)=gcd(a,b-a,c-b);所以知道这个性质就知道要用差分,这样的话每次区间加x只要更新l,r+1两个点,然后a怎么求因为是差分所以求和就好,这里可用线段树也可以树状数组。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e5+100;
struct node
{
int l,r,id;
int Max;
int gc;
};
node Tree[4*maxn];
int a[maxn],b[maxn];
int c[maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,int val)
{
for(int i=pos;i<maxn;i+=lowbit(i))
{
c[i]+=val;
}
return ;
}
int get_sum(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=c[i];
}
return sum;
}
int gcd(int x,int y)
{
if(y==0)
{
return x;
}
else
{
return gcd(y,x%y);
}
}
void push_up(int id)
{
Tree[id].Max=max(abs(Tree[id<<1].Max),abs(Tree[id<<1|1].Max));
Tree[id].gc=gcd(Tree[id<<1].gc,Tree[id<<1|1].gc);
return ;
}
void bulid(int l,int r,int id)
{
Tree[id].l=l;
Tree[id].r=r;
if(l==r)
{
Tree[id].Max=b[l];
Tree[id].gc=b[l];
return ;
}
int mid=(l+r)/2;
bulid(l,mid,id<<1);
bulid(mid+1,r,id<<1|1);
push_up(id);
return ;
}
void update(int pos,int val,int id)
{
if(Tree[id].l==pos&&Tree[id].l==Tree[id].r)
{
Tree[id].Max+=val;
Tree[id].gc+=val;
return ;
}
int mid=(Tree[id].l+Tree[id].r)/2;
if(pos<=mid)
{
update(pos,val,id<<1);
}
else
{
update(pos,val,id<<1|1);
}
push_up(id);
return ;
}
int get_ans(int l,int r,int id)
{
if(Tree[id].l>=l&&Tree[id].r<=r)
{
int MM=abs(Tree[id].Max);
return MM;
}
int mid=(Tree[id].l+Tree[id].r)/2;
int ans=0;
if(mid>=l)
{
ans=max(ans,abs(get_ans(l,r,id<<1)));
}
if(mid+1<=r)
{
ans=max(ans,abs(get_ans(l,r,id<<1|1)));
}
return ans;
}
int get_gcd(int l,int r,int id)
{
if(Tree[id].l>=l&&Tree[id].r<=r)
{
int MM=Tree[id].gc;
return MM;
}
int mid=(Tree[id].l+Tree[id].r)/2;
int ans=0;
if(mid>=l)
{
ans=gcd(ans,get_gcd(l,r,id<<1));
}
if(mid+1<=r)
{
ans=gcd(ans,get_gcd(l,r,id<<1|1));
}
return abs(ans);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i]-a[i-1];
}
bulid(1,n,1);
for(int i=1;i<=m;i++)
{
int opt,l,r;
scanf("%d",&opt);
if(opt==1)
{
int x;
scanf("%d%d%d",&l,&r,&x);
update(l,x,1);
if(r<n)
{
update(r+1,-x,1);
}
add(l,x);
add(r+1,-x);
}
else if(opt==2)
{
scanf("%d%d",&l,&r);
LL ans=0;
if(l!=r)
ans=get_ans(l+1,r,1);
printf("%lld\n",ans);
}
else
{
scanf("%d%d",&l,&r);
LL ans=1;
if(l!=r)
{
ans=get_gcd(l+1,r,1);
ans=gcd(ans,a[l]+get_sum(l));
}
else
{
ans=get_sum(l)+a[l];
}
printf("%lld\n",ans);
}
}
return 0;
}