小阳的贝壳(数论,线段树)

小阳的贝壳

题意:给出一个数组 a a a n n n个数, m m m次询问。有 3 3 3种询问, 1 , l , r , x ; 2 , l , r ; 3 , l , r 1,l,r,x;\quad2,l,r;\quad3,l,r 1,l,r,x;2,l,r;3,l,r
1 , l , r , x 1,l,r,x 1,l,r,x:对区间 [ l , r ] [l,r] [l,r]中的每个数加上 x x x
2 , l , r 2,l,r 2,l,r:询问 [ l , r ] [l,r] [l,r]区间里所有相邻数字的差(取绝对值) 的最大值。
3 , l , r 3,l,r 3,l,r:询问 [ l , r ] [l,r] [l,r]区间的所有数的最大公约数。

思路:用线段树维护数组 a a a的差分数组 c ( c [ i ] = a [ i ] − a [ i − 1 ] ) c(c[i] = a[i]-a[i-1]) c(c[i]=a[i]a[i1])。包括区间最大值,区间 g c d ( 最 大 公 约 数 ) gcd(最大公约数) gcd(),和区间和。

结论: g c d ( a 1 , a 2 , a 3 ) = g c d ( a 1 , a 2 , a 3 ) gcd(a_1,a_2,a_3) = gcd(a_1,a_2,a_3) gcd(a1,a2,a3)=gcd(a1,a2,a3) 推 广 到 a n 有 g c d ( a 1 , a 2 . . . , a n ) = g c d ( a 1 , a 2 − a 1... , a n − a n − 1 ) 推广到a_n有gcd(a_1,a_2...,a_n) = gcd(a_1,a_2-a1...,a_n-a_{n-1}) 广angcd(a1,a2...,an)=gcd(a1,a2a1...,anan1) g c d ( a 1 , a 2... , a n ) = g c d ( g c d ( a 1 , a 2.. a n 2 ) , g c d ( a n 2 + 1 , a n 2 + 2 . . . , a n ) ) gcd(a1,a2...,an)=gcd(gcd(a1,a2..a_{\frac{n}{2}}),gcd(a_{\frac{n}{2}+1},a_{\frac{n}{2}+2}...,a_n)) gcd(a1,a2...,an)=gcd(gcd(a1,a2..a2n),gcd(a2n+1,a2n+2...,an))所以可以直接用线段树维护差分数组 c c c来求区间 g c d gcd gcd

注意点:

  1. 对区间 [ l , r ] [l,r] [l,r]加上 x x x时, c [ l ] + = x , c [ r + 1 ] − = x ( 差 分 数 组 的 性 质 ) c[l]+=x,c[r+1]-=x(差分数组的性质) c[l]+=x,c[r+1]=x(),要特判 r + 1 < = n 。 r+1<=n。 r+1<=n
  2. 当查询为 2 , l , r 2,l,r 2,l,r时,我们得查询区间 [ l + 1 , r ] [l+1,r] [l+1,r]

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
int a[N], mx[N<<2], sum[N<<2], G[N<<2];
//分别为a数组;线段树维护的最大值数组,和数组,gcd数组。
//向上传递函数
void pushup(int num) {
    
    
    mx[num] = max(mx[num<<1], mx[num<<1|1]);
    G[num] = __gcd(G[num<<1], G[num<<1|1]);
    sum[num] = sum[num<<1|1] + sum[num<<1];
}
//构建线段树
void build(int l, int r, int num) {
    
    
    if(l == r) mx[num] = G[num] = abs(a[l]), sum[num] = a[l];
    else {
    
    
        int mid = l + r >> 1;
        build(l, mid, num<<1);
        build(mid+1, r, num<<1|1);
        pushup(num);
    }
}
//在区间[l,r]加上val。
void updata(int l, int r, int num, int pos, int val) {
    
    
    if(l == r) {
    
    
        a[l] += val;
        sum[num] = a[l];
        mx[num] = G[num] = abs(a[l]);
    }
    else {
    
    
        int mid = l + r >> 1;
        if(pos <= mid) updata(l, mid, num<<1, pos, val);
        else updata(mid+1, r, num<<1|1, pos, val);
        pushup(num);
    }
}
//查询和(a[en])
int query_sum(int l, int r, int st, int en, int num) {
    
    
    int mid = l + r >> 1;
    if(st <= l && r <= en) return sum[num];
    else if(en <= mid) return query_sum(l, mid, st, en, num<<1);
    else if(st > mid) return query_sum(mid+1, r, st, en, num<<1|1);
    else return query_sum(l, mid, st, en, num<<1) + query_sum(mid+1, r, st, en, num<<1|1);
}
//查询gcd
int query_G(int l, int r, int st, int en, int num) {
    
    
    int mid = l + r >> 1;
    if(st <= l && r <= en) return G[num];
    else if(en <= mid) return query_G(l, mid, st, en, num<<1);
    else if(st > mid) return query_G(mid+1, r, st, en, num<<1|1);
    else return __gcd(query_G(l, mid, st, en, num<<1), query_G(mid+1, r, st, en, num<<1|1));
}
//查询最大值
int query_mx(int l, int r, int st, int en, int num) {
    
    
    int mid = l + r >> 1;
    if(st <= l && r <= en) return mx[num];
    else if(en <= mid) return query_mx(l, mid, st, en, num<<1);
    else if(st > mid) return query_mx(mid+1, r, st, en, num<<1|1);
    else return max(query_mx(l, mid, st, en, num<<1), query_mx(mid+1, r, st, en, num<<1|1));
}
int main() {
    
    
    // freopen("in.txt", "r", stdin);
    int n, m, f, l, r, x;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    for(int i=n; i; i--) a[i] -= a[i-1];
    build(1, n, 1);
    for(int i=1; i<=m; i++) {
    
    
        scanf("%d%d%d", &f, &l, &r);
        if(f == 1) {
    
    
            scanf("%d", &x);
            updata(1, n, 1, l, x);
            if(r < n) updata(1, n, 1, r+1, -x);//注意点1.
        }
        else if(f == 2)    {
    
    
            if(l == r) printf("0\n");
            else printf("%d\n", query_mx(1, n, l+1, r, 1));//注意点2.
        }
        else {
    
    
            int t = query_sum(1, n, 1, l, 1);
            if(l == r) printf("%d\n", t);
            else printf("%d\n", __gcd(t, query_G(1, n, l+1, r, 1)));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45363113/article/details/108154269