zoukankan      html  css  js  c++  java
  • AcWing246区间最大公约数(线段树+数学)

    题目地址https://www.acwing.com/problem/content/247/

    题目描述:

    给定一个长度为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,M100000

    题解:这道题是区间修改和区间查询。但是由于最大公约数的特性,我们可以改为单点修改。(x,y,z....)的最大公约数与(x,y-x,z-y....)的最大公约数相同

    证明,只要证明前者的最大公约数是后者的公约数,并且后者的最大公约数是前者的公约数就可以了。假设,前者的最大公约数为d1,则x%d1=0,y%d1=0,z%d1=0....,那么显而易见x%d1=0,(y-x)%d1=0,(z-y)%d1=0.那么可以知道d1也是后者的公约数

    假设后者的最大公约数是d2,则x%d2=0,(y-x)%d2=0,(z-y)%d2=0.....,可以知道x%d2=0,y%d2=0,z%d2=0,...所以d2也是前者的公约数。

    通过上面这个数学知识,我们便可以利用差分数组来进行求解,那么区间加和就可以转换为两个单点修改。至于区间[l,r]的最大公约数,可以求出sum[l]和[l+1,r]的最大公约数,让二者再求公约数。注意线段树中存储的是元数组的差分数组。

    AC代码

    #include<iostream>
    #include<cmath>
    using namespace std;
    const int N=5e5+10;
    #define ll long long int
    struct node{
        int l,r;
        ll sum,gc;
    }tr[4*N];
    ll last=0,x;
    
    ll gcd(ll a,ll b){
        if(b==0) return a;
        return gcd(b,a%b);
    }
    
    struct node pushup(struct node &a,struct node &b,struct node &c){
        a.sum=b.sum+c.sum;
        a.gc=gcd(b.gc,c.gc);
        return a;
    }
    
    void pushup(int u){
        pushup(tr[u],tr[u<<1],tr[u<<1|1]);
    }
    
    void build(int u,int l,int r){
        tr[u].l=l,tr[u].r=r;
        if(l==r){
            cin>>x;
            tr[u].sum=x-last;
            tr[u].gc=x-last;
            last=x;
            return ;
        } 
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
        return ;
    }
    
    void modify(int u,int x,ll d){
        if(tr[u].l==x&&tr[u].r==x){
            tr[u].sum+=d;
            tr[u].gc+=d;
            return ;
        }
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=mid) modify(u<<1,x,d);
        if(x>mid) modify(u<<1|1,x,d);
        pushup(u);
        return ;
    }
    
    struct node query(int u,int l,int r){
        if(l>r) return node({0});
        if(tr[u].l>=l&&tr[u].r<=r){
            return tr[u];
        }
        int mid=tr[u].l+tr[u].r>>1;
        struct node a1,a2,a;
        if(l<=mid) a1=query(u<<1,l,r);
        if(r>mid) a2=query(u<<1|1,l,r);
        if(l<=mid&&r>mid) return pushup(a,a1,a2);
        else if(l<=mid) return a1;
        else return a2;
        
    }
    
    int main(){
        int n,m;cin>>n>>m;
        build(1,1,n);
        char ch;
        ll l,r,d;
        while(m--){
            cin>>ch>>l>>r;
            if(ch=='C'){
                cin>>d;
                modify(1,l,d);
                if(r<n) modify(1,r+1,-d);
            }
            else {
                struct node left=query(1,1,l),right;
                if(l+1<=r)  right=query(1,l+1,r);
                else {
                    right.gc=left.sum;
                }
                cout<<abs(gcd(left.sum,right.gc))<<endl;
            }
        }
        return 0;
    }

    写于:2020/8/28 9:19


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    linux运维、架构之路-Kubernetes离线、二进制部署集群
    linux运维、架构之路-Kubernetes集群部署
    创建SpringMVC项目过程
    Spring AOP使用方式
    Java动态代理
    Java工厂模式解耦 —— 理解Spring IOC
    Neural Turing Machine
    小米路由器mini刷锐捷
    目前深度学习开源数据集整理
    Spring编译后没有xml配置文件解决方法
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13575661.html
Copyright © 2011-2022 走看看