• AcWing:246. 区间最大公约数(线段树 + 增量数组(树状数组) + 差分序列)


    给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

    1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

    2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

    对于每个询问,输出一个整数表示答案。

    输入格式

    第一行两个整数N,M。

    第二行N个整数A[i]。

    接下来M行表示M条指令,每条指令的格式如题目描述所示。

    输出格式

    对于每个询问,输出一个整数表示答案。

    每个答案占一行。

    数据范围

    N500000,M100000N≤500000,M≤100000

    输入样例:

    5 5
    1 3 5 7 9
    Q 1 5
    C 1 5 1
    Q 1 5
    C 3 3 6
    Q 2 4
    

    输出样例:

    1
    2
    4

    算法:线段树 + 增量数组(树状数组) + 差分序列

    题解:

      性质:

    • gcd(a, b) = gcd(a, b - a)
    • gcd(a, b, c) = gcd(a, b - a, c - b)
    • acd(a1, a2, ... , an) = gcd(a1, a2 - a1, ... , an - an-1)

      利用这条性质来求解此题

    1. 对用询问“Q l r”来说,可以求出结果__gcd(arr[l], query(1, l + 1, r),就是同上面的性质,前面那个arr[l]就是性质里面的第一个数,后面的就是存在了线段树里面差分序列,求出(l + 1, r)区间的最大公约数即可。(其中的arr[l]等于原本数组里面的值加上后面更改的值,更改的值记录再树状数组里面)。
    2. 对于询问“C l r d”来说,只需要修改树状数组里面的值,以及线段树里面的值即可。

    注意:题目会爆int,需要用long long。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 5e5+7;
    
    struct node {
        ll l, r;
        ll dat;
    }tree[maxn << 2];   //维护差分序列的线段树
    
    ll n, m;
    ll d[maxn];         //差分数组
    ll arr[maxn];       //原始数组
    ll T[maxn];         //增量数组(树状数组)
    
    ll lowbit(ll x) {
        return x & (-x);
    }
    
    void pushup(ll root) {
        tree[root].dat = __gcd(tree[root << 1].dat, tree[root << 1 | 1].dat);
    }
    
    void build(ll root, ll l, ll r) {
        tree[root].l = l;
        tree[root].r = r;
        if(l == r) {
            tree[root].dat = d[l];
            return;
        }
        ll mid = (l + r) >> 1;
        build(root << 1, l, mid);
        build(root << 1 | 1, mid + 1, r);
        pushup(root);
    } 
    
    void add(ll x, ll val) {
        while(x <= n) {
            T[x] += val;
            x += lowbit(x);
        }
    }
    
    ll ask(ll x) {
        ll res = 0;
        while(x > 0) {
            res += T[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    void update(ll root, ll pos, ll val)  {
        ll l = tree[root].l;
        ll r = tree[root].r;
        if(l == r) {
            tree[root].dat += val;
            return;
        }
        ll mid = (l + r) >> 1;
        if(pos <= mid) {
            update(root << 1, pos, val);
        } else {
            update(root << 1 | 1, pos, val);
        }
        pushup(root);
    }
    
    ll query(ll root, ll x, ll y) {
        ll l = tree[root].l;
        ll r = tree[root].r;
        if(x <= l && r <= y) {
            return tree[root].dat;
        }
        ll mid = (l + r) >> 1;
        ll res = 0;
        if(x <= mid) {
            res = __gcd(res, query(root << 1, x, y));
        }
        if(y > mid) {
            res = __gcd(res, query(root << 1 | 1, x, y));
        }
        return abs(res);        //注意:这里需要加绝对值,因为可能出现负数
    }
    
    int main() {
        scanf("%lld%lld", &n, &m);
        for(ll i = 1; i <= n; i++) {
            scanf("%lld", &arr[i]);
            d[i] = arr[i] - arr[i - 1];         //构建差分数组
        }
        build(1, 1, n);
        while(m--) {
            char str[5];
            ll l, r, val;
            scanf("%s", str);
            if(str[0] == 'Q') {
                scanf("%lld %lld", &l, &r);
                ll now = arr[l] + ask(l);   //获取当前位置的值(原始数组 + 增量数组)
                printf("%lld
    ", __gcd(now, query(1, l + 1, r)));   //与后面的部分求最大公约数
            } else {
                scanf("%lld %lld %lld", &l, &r, &val);
                add(l, val);
                add(r + 1, -val);
                update(1, l, val);
                if(r < n) {     //判断是否会越界
                    update(1, r + 1, -val);
                }
            
            }
        }
        return 0;
    }
  • 相关阅读:
    PhpStorm中如何调整字体大小
    PhpStorm-2017.1.2破解步骤
    Eclipse/MyEclipse 最最常用的快捷键
    Invalid result location value/parameter
    系统重装--相关问题
    喜马拉雅||亲爱的,慢慢行走
    QQ聊天界面模式切换
    myeclipse中如何修改项目的名称
    软考-程序设计语言基础(编译原理)
    软考-计算机组成原理、体系机构与网络安全
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/11275241.html
Copyright © 2020-2023  润新知