Luogu T9376 区间GCD
Posted 青石巷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu T9376 区间GCD相关的知识,希望对你有一定的参考价值。
题目背景
无
题目描述
给定一长度为n的动态序列,请编写一种数据结构,要求支持m次操作,包括查询序列中一闭区间中所有数的GCD,与对一闭区间中所有数加上或减去一个值。
输入输出格式
输入格式:
第1行两个数n,m,表示序列长度和操作次数。
第2行n个数ai,表示给定序列。
第3行至第m+2行,每行3~4个数:
(1) 1 x y k 表示将[x,y]上的所有数加上k。
(2) 2 x y 表示询问[x,y]上所有数的GCD。
输出格式:
对所有操作2,输出一个数,表示询问结果。
输入输出样例
7 3 4 8 2 6 5 7 10 2 1 4 1 2 3 7 2 2 3
2 3
说明
定义:a,b∈Z时,gcd(a,b)=gcd(abs(a),abs(b))
对于30%的数据,n,m<=1000。
对于90%的数据,n,m<=100000。
对于100%的数据,n,m<=200000,ai<=1e7(初始),abs(k)<=1e7。
题解:
如果题目要求改为只支持区间查询,那么线段树或ST表都可以很方便地实现。进一步思考,区间修改无法用普通线段树实现的根本原因在于对[l,r]修改后[l,r]的结果无法O(1)计算出来。
如果区间修改改为单点修改,则可以用线段树暴力log(n)修改。
此处证明一个引理:gcd(a1,a2,a3,...,ai)=gcd(a1,a2-a1,a3-a2,...ai-ai-1).
设S为ai的公因数集合,T为ai-ai-1的公因数集合
设p为ai的任意一个公因数,则有p|ai,由整除的性质知p|ai-ai-1,则p一定是ai-ai-1的公因数,所以S是T的子集。
同理,设q为ai-ai-1的任意一个公因数,运用同样的性质可知q一定是ai的公因数,所以T是S的子集。
综上,S=T,所以max{S}=max{T},即gcd(a1,a2,a3,...,ai)=gcd(a1,a2-a1,a3-a2,...ai-ai-1).
所以我们将原数组a进行差分,设差分后数组为d,区间查询[l,r]则转化为gcd(gcd(d[l+1,r]),a[l]);差分后区间修改变为单点修改,可用线段树暴力实现。
具体操作:将原数组进行差分,用一棵支持单点修改的线段树维护gcd,将差分数组用一个树状数组维护前缀和(用来求出变化后的a[l],也可以合并在线段树中)。
注意:差分时对区间[l,r]涉及到对r+1的操作,为防止溢出,线段树区间增大至[1,n+1]。
代码如下:
以上是关于Luogu T9376 区间GCD的主要内容,如果未能解决你的问题,请参考以下文章