链接:https://ac.nowcoder.com/acm/problem/26255
来源:牛客网
题目描述
小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为 colicol_icoli 。现在小阳有 3 种操作:
1 l r x:给 [l,r][l,r][l,r] 区间里所有贝壳的颜色值加上 xxx 。
2 l r:询问 [l,r][l,r][l,r] 区间里所有相邻贝壳 颜色值的差(取绝对值) 的最大值(若 l=rl = rl=r 输出 0)。
3 l r :询问 [l,r][l,r][l,r] 区间里所有贝壳颜色值的最大公约数。
输入描述:
第一行输入两个正整数 n,mn,mn,m,分别表示贝壳个数和操作个数。
第二行输入 nnn 个数 colicol_icoli,表示每个贝壳的初始颜色。
第三到第 m+2m + 2m+2 行,每行第一个数为 optoptopt,表示操作编号。接下来的输入的变量与操作编号对应。
输出描述:
共 m 行,对于每个询问(操作 2 和操作 3)输出对应的结果。
思路
题目是关于区间修改和区间查询的,考虑线段树或者树状数组,舍去树状数组。
如何用线段树去写?如果只是维护原数组的话肯定是没办法解决问题的。
所以用线段树去维护差分数组 d [ ] d[] d[]。
对于操作1,对应于差分数组的 d [ l ] + x , d [ r + 1 ] − x d[l]+x,d[r+1]-x d[l]+x,d[r+1]−x操作。因此考虑用线段树进行单点修改。
对于操作2,求的是区间 [ l , r ] [l,r] [l,r]内 ∣ t i − t i − 1 ∣ ( l + 1 ) ≤ i ≤ j |t_i-t_{i-1}|(l+1)\leq i\leq j ∣ti−ti−1∣(l+1)≤i≤j的最大值,也就是差分数组的 d [ i ] d[i] d[i]的最大值。因子考虑用线段树维护 ∣ d [ i ] ∣ |d[i]| ∣d[i]∣的最大值
对于操作3,
g
c
d
(
t
l
,
t
l
+
1
,
t
l
+
2
,
…
,
t
r
)
=
g
c
d
(
t
l
,
∣
t
l
+
1
−
t
l
∣
,
…
,
∣
t
r
−
t
r
−
1
∣
)
gcd(t_l,t_{l+1},t_{l+2},…,t_{r})=gcd(t_l,|t_{l+1}-t_l|,…,|t_{r}-t_{r-1}|)
gcd(tl,tl+1,tl+2,…,tr)=gcd(tl,∣tl+1−tl∣,…,∣tr−tr−1∣)
= g c d ( t l , ∣ d l + 1 ∣ , ∣ d l + 2 ∣ , … , ∣ d r ∣ ) =gcd(t_l,|d_{l+1}|,|d_{l+2}|,…,|d_r|) =gcd(tl,∣dl+1∣,∣dl+2∣,…,∣dr∣)
= g c d ( ∑ i = 1 l d i , ∣ d l + 1 ∣ , … , ∣ d r ∣ ) =gcd(\sum_{i=1}^{l}d_i,|d_{l+1}|,…,|d_r|) =gcd(i=1∑ldi,∣dl+1∣,…,∣dr∣)
因此考虑用线段树维护区间内 ∣ d i ∣ |d_i| ∣di∣的最小公倍数和其区间和。
综上所述,线段树节点包含的信息有,区间内 d i d_i di的和、区间内 ∣ d i ∣ |d_i| ∣di∣的最大公约数、区间内 d i d_i di的值。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define debug(case,x); cout<<case<<" : "<<x<<endl;
#define open freopen("ii.txt","r",stdin)
#define close freopen("oo.txt","w",stdout)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pb push_back
using namespace std;
#define int long long
#define lson rt<<1
#define rson rt<<1|1
const int maxn=1e5+10;
int t[maxn],d[maxn];
struct tree{
int l,r;
int sum,maxx,gcd;
}tree[maxn<<2];
void push_up(int rt){
tree[rt].sum=tree[lson].sum+tree[rson].sum;
tree[rt].gcd=__gcd(tree[lson].gcd,tree[rson].gcd);
tree[rt].maxx=max(tree[lson].maxx,tree[rson].maxx);
}
void build(int rt,int l,int r){
tree[rt].l=l,tree[rt].r=r;
if(l==r){
tree[rt].maxx=tree[rt].gcd=abs(d[l]);
tree[rt].sum=d[l];
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(rt);
}
void update_point(int rt,int x,int k){
if(tree[rt].l==x&&tree[rt].r==x){
tree[rt].sum+=k;
tree[rt].maxx=tree[rt].gcd=abs(tree[rt].sum);
return ;
}
int mid=(tree[rt].r+tree[rt].l)>>1;
if(x<=mid)update_point(lson,x,k);
else update_point(rson,x,k);
push_up(rt);
}
int query_sum(int rt,int l,int r){
if(tree[rt].l>=l&&tree[rt].r<=r){
return tree[rt].sum;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
int res=0;
if(l<=mid){
res+=query_sum(lson,l,r);
}
if(r>mid){
res+=query_sum(rson,l,r);
}
return res;
}
int query_gcd(int rt,int l,int r){
if(l<=tree[rt].l&&tree[rt].r<=r)
return tree[rt].gcd;
int mid=(tree[rt].l+tree[rt].r)>>1;
int res=0;
if(l<=mid) res=__gcd(res,query_gcd(lson,l,r));
if(r>mid) res=__gcd(res,query_gcd(rson,l,r));
return res;
}
int query_max(int rt,int l,int r){
if(tree[rt].l>=l&&tree[rt].r<=r)
return tree[rt].maxx;
int mid=(tree[rt].l+tree[rt].r)>>1;
int res=0;
if(l<=mid) res=max(res,query_max(lson,l,r));
if(r>mid) res=max(res,query_max(rson,l,r));
return res;
}
signed main(){
int n,m;scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&t[i]);
d[i]=t[i]-t[i-1];
}
build(1,1,n);
while(m--){
int op,l,r;scanf("%lld%lld%lld",&op,&l,&r);
if(op==1){
int x;scanf("%lld",&x);
update_point(1,l,x);
if(r<n) update_point(1,r+1,-x);
}else if(op==2){
if(l==r)printf("0\n");
else printf("%lld\n",query_max(1,l+1,r));
}else{
printf("%lld\n",__gcd(query_sum(1,1,l),query_gcd(1,l+1,r)));
}
}
}