题目背景

题目描述

给定一长度为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,输出一个数,表示询问结果。

输入输出样例

输入样例#1:

7 3
4 8 2 6 5 7 10
2 1 4
1 2 3 7
2 2 3

输出样例#1:

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]。

代码如下:

#include<bits/stdc++.h>
#define LL long long
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=2e5+10;
LL node[4*maxn],a[maxn],c[maxn],d[maxn];
int n,m;LL ans;
LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
void pushup(int x){node[x]=abs(gcd(node[x<<1],node[x<<1|1]));}
void build(int x,int l,int r) {
    if(l==r){node[x]=d[l];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}
void change(int x,int l,int r,int pos,int d) {
    if(l==r){node[x]+=d;return;}
    int mid=(l+r)>>1;
    if(pos<=mid){change(x<<1,l,mid,pos,d);}
    else{change(x<<1|1,mid+1,r,pos,d);}
    pushup(x);
}
void query(int x,int l,int r,int sj,int tj) {
    if(sj<=l&&r<=tj){ans=abs(gcd(node[x],ans));return;}
    int mid=(l+r)>>1;
    if(sj<=mid){query(x<<1,l,mid,sj,tj);}
    if(mid+1<=tj){query(x<<1|1,mid+1,r,sj,tj);}
    pushup(x);
}
void add(int x,int d) {
    int i;
    for(i=x;i<=n;i+=lowbit(i)){c[i]+=d;}
}
LL sum(int x) {
    int i;LL ans=0;
    for(i=x;i>=1;i-=lowbit(i)){ans+=c[i];}
    return ans;
}
int main() {
    int i,j,flag,l,r,dlt;
    cin>>n>>m;
    for(i=1;i<=n;i++){scanf("%lld",&a[i]);}
    n++;
    for(i=1;i<=n;i++){d[i]=a[i]-a[i-1];add(i,d[i]);}
    build(1,1,n);
    //for(i=1;i<=3*n;i++){printf("i=%d node[i]=%d\n",i,node[i]);}
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&flag,&l,&r);
        if(flag==1){scanf("%d",&dlt);change(1,1,n,l,dlt);change(1,1,n,r+1,-dlt);add(l,dlt);add(r+1,-dlt);}
        else{ans=0;query(1,1,n,l+1,r);/*printf("ans=%d sum(l)=%d\n",ans,sum(l));*/printf("%lld\n",abs(gcd(ans,sum(l))));}
    }
    return 0;
}

转载于:https://www.cnblogs.com/XSC637/p/7423923.html

Luogu T9376 区间GCD相关推荐

  1. luogu P5142 区间方差(线段树、乘法逆元)

    luogu P5142 区间方差 本题要求维护模区间方差,很明显是一道数据结构题. 我们化简方差公式: 而平均数等于 可以发现,我们只需要维护序列的区间和和区间平方和,就可以维护平均数和方差. 区间和 ...

  2. HDU5726 线段树求解区间GCD

    GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submi ...

  3. Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD

    题意: 两个操作, 单点修改 询问一段区间是否能在至多一次修改后,使得区间$GCD$等于$X$ 题解: 正确思路; 线段树维护区间$GCD$,查询$GCD$的时候记录一共访问了多少个$GCD$不被X整 ...

  4. 区间gcd (带修) 线段树

    题目链接:https://ac.nowcoder.com/acm/contest/1033/B 再次吐槽CH 区间gcd再加区间修改. 一般求gcd的时候辗转相除法. gcd(x,y)=gcd(x,y ...

  5. Luogu P6055 [RC-02] GCD(莫比乌斯反演,杜教筛)(这题乐死我了,真就图一乐呗)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/P6055 Prob ...

  6. 线段树 区间加 gcd 差分

    小阳的贝壳 如果线段树要维护区间gcd 这个很简单,但是如果有了区间加,维护gcd 就比较麻烦了. 这个首先可以证明的是 gcd(x,y,z)=gcd(x,y-x,z-y)   这个可以推到 n 个 ...

  7. 等差区间 线段树+GCD

    Description 已知一个长度为 nn 的数组 a[1],a[2],-,a[n]a[1],a[2],-,a[n],我们进行 qq 次询问,每次询问区间 a[l],a[l+1],-,a[r−1], ...

  8. 【HDU - 5869】Different GCD Subarray Query(思维,数学,gcd,离线处理,查询区间不同数,树状数组 或 二分RMQ)

    题干: This is a simple problem. The teacher gives Bob a list of problems about GCD (Greatest Common Di ...

  9. [HDOJ5869] Different GCD Subarray Query(RMQ,树状数组,离线)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:n个数,q次询问,问区间内gcd不同值的个数. 和dquery那道题一样,也是离线的做法. ...

最新文章

  1. 2022-2028年中国文化旅游业投资分析及前景预测报告(上中下卷)
  2. 他24岁,4篇Nature在手,也会关心学不懂C语言怎么办
  3. 获取图像的梯度,方向和方向梯度图像
  4. PHP7CMS 无条件前台GETSHELL
  5. Linux后台运行和关闭程序、查看后台任务
  6. BZOJ2131免费的馅饼 DP+树状数组
  7. 【操作系统】对操作系统的了解
  8. 【bzoj2555】Substring【后缀平衡树入门】
  9. android 申请usb权限,USB 权限申请流程
  10. java并发之Future与Callable使用
  11. Java并发编程之线程池中的Future
  12. UVA12542 LA6149 Prime Substring【筛选法+贪心】
  13. camunda 流程执行追踪_流程引擎为什么选 Camunda
  14. Eview操作步骤——数据导入及数据建模
  15. Si4438, Si4432, Sx1278, Sx1276, Sx1212无线数传模块简单介绍
  16. C# NPOI Excel 合并单元格和取消单元格
  17. Cloudera Manager 环境搭建
  18. 职业生涯必备——程序员“黑话”指南
  19. 荒野猎人 但是亲眼看到还是第一次
  20. 【Java】session.getAttribute出现[classes/:na]报错如何解决

热门文章

  1. Linux apache2将目录从/var/www/html调整为/根目录时报错:You don‘t have permission to access / on this server
  2. 设置nginx开机启动
  3. Builder建造者设计模式
  4. zookeeper的安装及配置教程(步骤详尽)
  5. 雷蛇鼠标宏文件_Razer推出DeathAdder V2与Basilisk V2游戏鼠标
  6. html两条下划线重叠,文字和text-decoration:underline下划线重叠问题
  7. C++11:move移动语义
  8. 线性规划总结3——单纯形法和对偶单纯形法
  9. RTD-D项目总结(MATLAB)
  10. 单线程和多线程的区别_谷歌下载东西超慢?开启Chrome多线程下载,下载速度提升10倍+...