首页 > 其他分享 >acwing246 区间最大公约数

acwing246 区间最大公约数

时间:2024-06-18 23:44:37浏览次数:16  
标签:Info std acwing246 gcd int i64 最大公约数 info 区间

给定长度为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(a,b,c) = gcd(a,b-a,c-d) = gcd(a, gcd(b-a,c-d)),因此可以拆成两部分计算,左边是前缀和,右边是区间gcd,二者都可以用线段树来维护。

#include <bits/stdc++.h>
using i64 = long long;

i64 mygcd(i64 x, i64 y) {
    return y ? mygcd(y, x%y) : x;
}

template<class Info>
struct SegmentTree {
    int n;
    std::vector<Info> info;
    SegmentTree():n(0) {}
    SegmentTree(int _n, Info v = Info()) {
        init(_n, v);
    }
    void init(int _n, Info v = Info()) {
        init(std::vector<Info>(_n, v));
    }
    template<class T>
    SegmentTree(std::vector<T> v) {
        init(v);
    }
    template<class T>
    void init(std::vector<T> v) {
        n = v.size();
        info.assign(4 << std::__lg(n), Info());
        std::function<void(int,int,int)> build = [&](int x, int l, int r) {
            if (l + 1 == r) {
                info[x] = v[l]; //fixme
                return;
            }
            int m = (l + r) / 2;
            build(2*x+1, l, m);
            build(2*x+2, m, r);
            pushup(x);
        };
        build(0, 0, n);
    }
    void pushup(int x) {
        info[x] = info[2*x+1] + info[2*x+2];
    }
    void modify(int x, int l, int r, int p, const Info &v) {
        if (l + 1 == r) {
            info[x].gcd = info[x].gcd + v.gcd; //fixme
            info[x].sum = info[x].sum + v.sum;
            return;
        }
        int m = (l + r) / 2;
        if (p < m) {
            modify(2*x+1, l, m, p, v);
        } else {
            modify(2*x+2, m, r, p, v);
        }
        pushup(x);
    }
    void modify(int p, const Info &v) {
        modify(0, 0, n, p, v);
    }
    Info rangeQuery(int x, int l, int r, int L, int R) {
        if (R <= l || r <= L) {
            return Info();
        }
        if (L <= l && r <= R) {
            return info[x];
        }
        int m = (l + r) / 2;
        return rangeQuery(2*x+1, l, m, L, R) + rangeQuery(2*x+2, m, r, L, R);
    }
    Info rangeQuery(int L, int R) {
        return rangeQuery(0, 0, n, L, R);
    }
    template<class F>
    int findFirst(int x, int l, int r, int L, int R, F pred) {
        if (R <= l || r <= L || !pred(info[x])) {
            return -1;
        }
        if (l + 1 == r) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2*x+1, l, m, L, R, pred);
        if (res == -1) {
            res = findFirst(2*x+2, m, r, L, R, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int L, int R, F pred) {
        return findFirst(0, 0, n, L, R, pred);
    }
    template<class F>
    int findLast(int x, int l, int r, int L, int R, F pred) {
        if (R <= l || r <= L || !pred(info[x])) {
            return -1;
        }
        if (l + 1 == r) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findLast(2*x+2, m, r, L, R, pred);
        if (res == -1) {
            res = findLast(2*x+1, l, m, L, R, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int L, int R, F pred) {
        return findLast(0, 0, n, L, R, pred);
    }
};

struct Info {
    i64 gcd, sum;
    Info(i64 v=0):gcd(v),sum(v) {}
    friend Info operator+(const Info &a, const Info &b) {
        Info ans;
        ans.gcd = mygcd(a.gcd, b.gcd);
        ans.sum = a.sum + b.sum;
        return ans;
    }
};

void solve() {
    int N, M;
    std::cin >> N >> M;
    std::vector<i64> A(N), B(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }
    std::adjacent_difference(A.begin(), A.end(), B.begin());
    SegmentTree<Info> seg(B);
    for (int i = 0; i < M; i++) {
        std::string op;
        i64 l, r, d;
        std::cin >> op >> l >> r;
        l--, r--;
        if (op == "C") {
            std::cin >> d;
            seg.modify(l, Info(d));
            if (r + 1 < N) {
                seg.modify(r+1, Info(-d));
            }
        } else if (op == "Q") {
            i64 gcd1 = seg.rangeQuery(0, l+1).sum;
            i64 gcd2 = seg.rangeQuery(l+1, r+1).gcd;
            std::cout << std::abs(mygcd(gcd1, gcd2)) << "\n";
        }
    }
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

标签:Info,std,acwing246,gcd,int,i64,最大公约数,info,区间
From: https://www.cnblogs.com/chenfy27/p/18255412

相关文章

  • C++数据格式化3 - 格式化时间区间(使用时长)
    1.关键词2.strfmt.h3.strfmt.cpp4.测试代码5.运行结果6.源码地址1.关键词关键字:C++数据格式化字符串处理std::string时间区间跨平台应用场景:想对一个时间区间(如用时:2000s)进行格式化,转化成人类易读的时分秒的格式。2.strfmt.h#pragmaonce#include......
  • NumPy 差分、最小公倍数、最大公约数、三角函数详解
    NumPy差分离散差分意味着相邻元素之间的减法。例如,对于[1,2,3,4],离散差分将是[2-1,3-2,4-3]=[1,1,1]要找到离散差分,使用diff()函数。示例:importnumpyasnparr=np.array([10,15,25,5])newarr=np.diff(arr)print(newarr)返回:[510-20],因为15-......
  • 79、最大不相交区间数量
    最大不相交区间数量题目描述给定N个闭区间[ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。输出可选取区间的最大数量。输入格式第一行包含整数N,表示区间数。接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。输出格式输出一个整数,表示......
  • 从CF1879D学习一类区间贡献题思路
    https://codeforces.com/contest/1879/problem/D关键在于互换两个\(\sum\)​的顺序一般像这样计算所有子区间的式子,如果要优化成接近线性,有一种可行思路是把注意力放在右端点,通过不断移动右端点,在移动的时候利用前面的统计结果算出移动右端点后的结果,从而得出所有子区间的答......
  • 代码随想录算法训练营第第37天 | 56. 合并区间 、738.单调递增的数字、968.监控二叉
    合并区间本题也是重叠区间问题,如果昨天三道都吸收的话,本题就容易理解了。https://programmercarl.com/0056.合并区间.html能做出来/***@param{number[][]}intervals*@return{number[][]}*/varmerge=function(intervals){intervals.sort((a,b)=>{......
  • 代码随想录算法训练营第三十七天 | 56.合并区间 738.单调递增的数字
    56.合并区间题目链接文章讲解视频讲解思路:  按左区间排序;  遍历所有区间,如果当前区间的左边界小于等于上一个区间的右边界,则合并区间(新区间的左边界为上一个区间的左边界,新区间的右边界为上一个区间的有边界和当前区间有边界中较大的一个)classSolution{public:......
  • 对于一个数字串,如何确定某段区间出现的数字是否都是偶数次
    本章对标:D-ThreeDaysAgo问题非常简单,也就是求出所有连续区间且这个区间内的数字都出现了偶数次的总合法区间数那么很明显有中\(O(n^2)\)的算法,但复杂度不够,那么枚举区间不行,从别的方面入手,考虑到每个字符只能是数字,那么我们此时可以将其转化为一个二进制串,表示的含义就是......
  • 龙哥量化:通达信压力区间买卖点,买卖提示突破为主升浪
    如果您需要代写公式,请联系我。龙哥QQ:591438821龙哥微信:Long622889STICKLINE(C>=O,H,L,0,0),colorred;STICKLINE(C>=O,C,O,10,10),colorred;STICKLINE(C=OANDC<REF(C,1),H,L,0,0),colorcyan;STICKLINE(C=OANDC<REF(C,1),C,O,10,0),colorcyan;STICKLINE(C<O,H,L,0,0......
  • 代码随想录算法训练营第第36天 | 452. 用最少数量的箭引爆气球、435. 无重叠区间、763
    今天的三道题目,都算是重叠区间问题,大家可以好好感受一下。都属于那种看起来好复杂,但一看贪心解法,惊呼:这么巧妙!这种题还是属于那种,做过了也就会了,没做过就很难想出来。不过大家把如下三题做了之后,重叠区间基本上差不多了用最少数量的箭引爆气球https://programmercarl.co......
  • 合并区间
    Problem:56.合并区间目录思路解题方法复杂度Code1这个写的有点不优美了丑Code2思路bite数组与排序两种思路解题方法描述你的解题方法复杂度时间复杂度:添加时间复杂度,示例:$O(n)$空间复杂度:添加空间复杂度,示例:$O(n)$Code1这个写的有点不优美了丑......