牛客小白月赛16 H 小阳的贝壳 (差分+线段树)

链接: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

备注:

1n,m105,1coli,x103,1opt3,1lrn

思路:
因为gcd(a,b) == gcd(a,b-a),那么我们把原数组差分一下,这样区间修改就只用修改两个点了,求相邻两点的差值也是一样的,线段树上多维护个mx[]就好了

实现代码:
#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid ll m = (l + r) >> 1
const ll M = 2e5+10;
ll a[M],b[M],c[M],sum[M<<2],mx[M<<2],n;
ll lowbit(ll x)
{
    return x & -x;
}
void add(ll x,ll val){
    for(ll i = x;i <= M;i += lowbit(i)){
        c[i] += val;
    }
}

ll getsum(ll x){
    ll ans = 0;
    for(ll i = x;i > 0;i -= lowbit(i)){
        ans += c[i];
    }
    return ans;
}

void up(ll rt){
    sum[rt] = __gcd(sum[rt<<1] ,sum[rt<<1|1]);
    mx[rt] = max(abs(mx[rt<<1]),abs(mx[rt<<1|1]));
}

void build(ll l,ll r,ll rt){
    if(l == r){
        sum[rt] = b[l];
        mx[rt] = b[l];
        return ;
    }
    mid;
    build(lson); build(rson);
    up(rt);
}

void update(ll p,ll c,ll l,ll r,ll rt){
    if(l == r){
        sum[rt] += c;
        mx[rt] += c;
        return ;
    }
    mid;
    if(p <= m) update(p,c,lson);
    else update(p,c,rson);
    up(rt);
}

ll query_gcd(ll L,ll R,ll l,ll r,ll rt){
    if(L <= l&&R >= r){
        return sum[rt];
    }
    mid;
    ll ret = 0;
    if(L <= m) ret = __gcd(ret,query_gcd(L,R,lson));
    if(R > m) ret = __gcd(ret,query_gcd(L,R,rson));
    return abs(ret);
}

ll query_max(ll L,ll R,ll l,ll r,ll rt){
    if(L <= l&&R >= r){
        return mx[rt];
    }
    mid;
    ll ret = 0;
    if(L <= m) ret = max(ret,abs(query_max(L,R,lson)));
    if(R > m) ret = max(ret,abs(query_max(L,R,rson)));
    return ret;
}



int main()
{
    ll m,l,r,x;
    scanf("%lld%lld",&n,&m);
    for(ll i = 1;i <= n;i ++) scanf("%lld",&a[i]),b[i]=a[i]-a[i-1];
    build(1,n,1);
    ll op;
    for(ll i = 1;i <= m;i ++){
        scanf("%lld",&op);
        if(op == 1){
            scanf("%lld%lld%lld",&l,&r,&x);
            update(l,x,1,n,1);
            if(r < n) update(r+1,-x,1,n,1);
            add(l,x); add(r+1,-x);
        }
        else if(op == 2){
            scanf("%lld%lld",&l,&r);
            ll ans;
            if(l!=r)
            ans = query_max(l+1,r,1,n,1);
            else
            ans = 0;
            printf("%lld\n",ans);
        }
        else {
            scanf("%lld%lld",&l,&r);
            ll cnt = a[l] + getsum(l);
            if(l != r){
            ll ans = query_gcd(l+1,r,1,n,1);
            printf("%lld\n",__gcd(cnt,ans));
            }
            else {
                printf("%lld\n",cnt);
            }
        }
    }
    return 0;
}

 

 
posted @ 2019-07-13 13:16  冥想选手  阅读(571)  评论(0编辑  收藏  举报