小阳的贝壳

链接

题目描述

小阳手中一共有 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;
}
posted @ 2020-12-16 17:24  肆之月  阅读(95)  评论(0编辑  收藏  举报