AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 246. $\Large\color{blue}{【算法提高课】区间最大公约数(线段树)}$    原题链接    困难

作者: 作者的头像   incra ,  2022-11-19 10:54:01 ,  所有人可见 ,  阅读 3002


47


<—点个赞吧QwQ

宣传一下算法提高课整理{:target=”_blank”}

给定一个长度为 $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$ 条指令,每条指令的格式如题目描述所示。

输出格式

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

每个答案占一行。

数据范围

$N \\le 500000, M \\le 100000$,
$1 \\le A\[i\] \\le 10^{18}$,
$|d| \\le 10^{18}$

输入样例:

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,a-b\}}$,变化一下这个柿子,发现$\gcd{\{a,b,c\}}$就是$\gcd{\{\gcd{\{a,b\}},\gcd{\{b,c\}}\}}$,也就是$\gcd{\{a,b-a,c-a\}}$。相信细心的同学们已经发现,以下规律:$\gcd{\{a_1,a_2,\dots,a_n\}}=\gcd{\{a_1,a_2-a_1,\dots,a_n-a_{n-1}\}}$
最后查询时要注意,代码中第$i$个数的$d$是指$a_i-a_{i-1}$,所以当我们查询$[l,r]$的区间最大公约数时,我们要用$[l+1,r]$的$\gcd$和$a_l$求最大公约数。

代码

#include <iostream>
using namespace std;
typedef long long LL;
const int N = 500010;
int n,m;
LL a[N];
struct segment_tree_node {
    int l,r;
    LL sum,d;
}tr[4 * N];
LL gcd (LL a,LL b) {
    return b ? gcd (b,a % b) : a;
}
void push_up (segment_tree_node &root,segment_tree_node &left,segment_tree_node &right) {
    root.sum = left.sum + right.sum;
    root.d = gcd (left.d,right.d);
}
void push_up (int u) {
    push_up (tr[u],tr[u << 1],tr[u << 1 | 1]);
}
void build_segment_tree (int u,int l,int r) {
    if (l == r) {
        LL b = a[l] - a[l - 1];
        tr[u] = {l,r,b,b};
    }
    else {
        tr[u].l = l,tr[u].r = r;
        int mid = l + r >> 1;
        build_segment_tree (u * 2,l,mid),build_segment_tree (u * 2 + 1,mid + 1,r);
        push_up (u);
    }
}
void modify (int u,int x,LL d) {
    if (tr[u].l == x && tr[u].r == x) {
        LL b = tr[u].sum + d;
        tr[u] = {x,x,b,b};
    }
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) modify (u * 2,x,d);
        else modify (u * 2 + 1,x,d);
        push_up (u);
    }
}
segment_tree_node query (int u,int l,int r) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u];
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        if (r <= mid) return query (u * 2,l,r);
        else if (l > mid) return query (u * 2 + 1,l,r);
        else {
            segment_tree_node left = query (u * 2,l,r);
            segment_tree_node right = query (u * 2 + 1,l,r);
            segment_tree_node ans;
            push_up (ans,left,right);
            return ans;
        }
    }
}
int main () {
    cin >> n >> m;
    for (int i = 1;i <= n;i++) cin >> a[i];
    build_segment_tree (1,1,n);
    while (m--) {
        char ch;
        int l,r;
        LL d;
        cin >> ch >> l >> r;
        if (ch == 'C') {
            cin >> d;
            modify (1,l,d);
            if (r + 1 <= n) modify (1,r + 1,- d); 
        }
        else {
            segment_tree_node left = query (1,1,l),right ({0,0,0,0});
            if (l + 1 <= r) right = query (1,l + 1,r);
            cout << abs (gcd (left.sum,right.d)) << endl;   //gcd (原序列中第l个数,[l+1,r]的d)
        }
    }
    return 0;
}

59 评论


用户头像
wh2011   2023-09-03 20:24      3    踩      回复

incra=懒猫

柿子还没改

用户头像
incra   2024-01-16 17:34         踩      回复

早就改了

用户头像
wh2011   2024-01-17 18:35    回复了 incra 的评论         踩      回复

,变化一下这个柿子,发现 没改呀

用户头像
incra   2024-01-17 18:36    回复了 wh2011 的评论      2    踩      回复

谐音可以吗(

用户头像
wh2011   2024-01-18 20:47    回复了 incra 的评论         踩      回复

6


用户头像
xyh2   2022-12-08 16:51      2    踩      回复

大佬,我有个不明白的地方,为什么那个是查询和普通线段树的查询是不一样的.

用户头像
jatro13   2023-09-03 23:09         踩      回复

当然不一样,普通线段树找的是和或最小/大值,我们现在想找gcd


用户头像
Conan15   2023-08-02 12:30      1    踩      回复

公式也写错了,应该是 $\gcd(a,b-a,c-b)$,我acwing花括号转义炸了

用户头像
incra   2023-08-02 13:47         踩      回复

那个是AcWing的问题,你试试\\{

用户头像
incra   2023-08-02 13:47    回复了 incra 的评论         踩      回复

或者\lbrace

用户头像
Conan15   2023-08-02 14:16    回复了 incra 的评论         踩      回复

你说得对,但是$\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{\\{$

用户头像
Conan15   2023-08-02 14:16    回复了 incra 的评论         踩      回复

你还是没改

用户头像
Conan15   2023-08-02 14:16    回复了 incra 的评论      1    踩      回复

谢谢

用户头像
incra   2023-08-03 13:03    回复了 Conan15 的评论         踩      回复

懒得改了

用户头像
incra   2023-08-03 13:03    回复了 Conan15 的评论         踩      回复

太老的题解,没人看

用户头像
Conan15   2023-08-03 13:43    回复了 incra 的评论      1    踩      回复

真·没人看,我们俩看了所以我们俩不是人

用户头像
incra   2023-08-03 14:23    回复了 Conan15 的评论      1    踩      回复

都是神(

用户头像
流苏贺风   2023-08-09 11:47         踩      回复

在 acwing 上见过的最新的评论,才六天前!!!

用户头像
incra   2023-08-09 12:11    回复了 流苏贺风 的评论         踩      回复

QwQ

用户头像
Empty_Sky   2023-08-11 18:15    回复了 incra 的评论      1    踩      回复

屡教不改,打屁股!

用户头像
incra   2023-11-12 18:47    回复了 Conan15 的评论         踩      回复

改了,上次太懒了

用户头像
Conan15   2023-11-13 21:16    回复了 incra 的评论         踩      回复

烤估


用户头像
xyh2   2022-12-08 19:16      1    踩      回复

可以把你qq发我一下吗,大佬,感觉在评论区问问题不太方便。hhh

用户头像
incra   2022-12-08 20:18      1    踩      回复

hh
我没有qq

用户头像
incra   2022-12-08 20:20         踩      回复

用AC Chat

用户头像
acwing_xyy   2023-10-02 19:58    回复了 incra 的评论         踩      回复

《没有qq》

用户头像
incra   2023-10-02 20:11    回复了 acwing_xyy 的评论      1    踩      回复

现在有了(((


用户头像
xyh2   2022-12-08 16:52      1    踩      回复

普通线段树是不是r>mid和l<=mid.就是第一个题目,这里想半天了

用户头像
incra   2022-12-08 17:02         踩      回复

对

用户头像
incra   2022-12-08 17:03      1    踩      回复

这题是我原先的代码,所以用的是结构体,很麻烦

用户头像
incra   2022-12-08 17:03      1    踩      回复

这里还用了差分

用户头像
xyh2   2022-12-08 19:11    回复了 incra 的评论         踩      回复

所以这里为什么不可以像普通线段树一样处理呢,我很不理解。

用户头像
xyh2   2022-12-08 19:12    回复了 incra 的评论         踩      回复

他这种的处理的话,好需要价格特判,但是我不知道为什么要这样。希望博主给我解答一下

用户头像
incra   2022-12-08 20:19    回复了 xyh2 的评论         踩      回复

价格?

用户头像
incra   2023-01-20 12:28    回复了 xyh2 的评论      1    踩      回复

因为有时要用结构体的sum,有时要用d,所以要返回结构体

用户头像
incra   2023-01-20 12:28    回复了 xyh2 的评论      1    踩      回复

当然也可以写两个查询函数

用户头像
incra   2023-01-20 12:29    回复了 xyh2 的评论         踩      回复

刚刚想明白了qwq

用户头像
incra   2023-05-19 19:05         踩      回复

这里再讲一下,你在查询时,会用到左子树的sum和d和右子树的sum和d,但是直接传一个pair不方便,所以就传一个节点node

用户头像
incra   2023-05-19 19:05         踩      回复

对不起,这个问题我磕到现在才想明白

用户头像
incra   2023-08-02 13:48    回复了 xyh2 的评论         踩      回复

你看了么


用户头像
xyh2   2022-12-08 16:52      1    踩      回复

普通线段树是不是r>mid和l<=mid.就是第一个题目,这里想半天了


用户头像
xyh2   2022-12-08 16:51      1    踩      回复

大佬,我有个不明白的地方,为什么那个是查询和普通线段树的查询是不一样的.


用户头像
wz150432   2025-06-25 21:40 · 北京         踩      回复

你的代码现在过不了,因为数据出了l == r的情况


用户头像
notTrueLight   2024-12-25 16:04         踩      回复

考古.gif


用户头像
2020luke   2024-07-23 10:15         踩      回复

不是为什么在acwing这种抄别人代码的垃圾题解会有人点赞啊???


用户头像
2020luke   2024-07-23 10:13         踩      回复

要点脸吧,代码不能自己写必须别人喂到你嘴里你改改改马蜂交上去是吧

用户头像
incra   2024-07-23 17:17         踩      回复

求别喷了,当时是只傻逼 xxs


用户头像
SFLS_AK_IOI   2024-07-23 09:50         踩      回复

码风狗屎

用户头像
incra   2024-07-23 17:24         踩      回复

求别喷了,当时是只傻逼 xxs


用户头像
blink.   2023-09-25 23:24         踩      回复

求(l,r)的gcd为什么要先算(1,l)呢?

用户头像
incra   2023-09-26 17:58         踩      回复

$1.l$ 的和等于第 $l$ 个元素的值


用户头像
Conan15   2023-08-02 12:27         踩      回复

变化一下这个柿子,你还是没改(


用户头像
Conan15   2023-08-02 12:26         踩      回复

已经发现,一下规律

要改成“已经发现以下规律”


用户头像
Conan15   2023-08-02 12:24         踩      回复

hpzc


用户头像
吴下阿蒙_吕子明   2023-07-21 09:53         踩      回复

有错别字 好难受能麻烦大佬改一下吗 式子不是柿子

用户头像
incra   2023-07-21 20:32         踩      回复

哦

用户头像
incra   2023-07-21 20:32         踩      回复

明天改一下


用户头像
acwing_67978   2023-06-02 10:59         踩      回复

大佬,这道题用懒标记可行吗?感觉pushudown()操作不是很好维护最大公约数?

用户头像
αγ   2023-07-11 15:11         踩      回复

可以的,但是用不着吧,pushdown()不好写,反正我是能不写就不写


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息