zoukankan      html  css  js  c++  java
  • bzoj 5028小Z的加油店(D12 序列gcd)(线段树+树状数组)

    题意

    给定一个序列有两种操作,一种是求一段区间的gcd,另一种是给一段区间加上一个值。(至于为什么看出来是区间gcd,题意应该是在这个区间的瓶子里面倒来倒去,最后要将一个瓶子的油给客户,然后根据裴蜀定理什么的就可以知道了

    题解

    根据更相减损术可知gcd(x,y)=gcd(x,y-x),那么易得对于三个数gcd(x,y,z)=gcd(x,y-x,z-y);

    用数学归纳法容易证明该性质堆任意多个整数都成立

    上面的式子有没有很像差分?

    所以我们就可以使用差分将区间修改变成两个单点修改,在修改时只要知道a[l]和[l+1,r]这段差分区间的gcd即可。

    对于差分数组我们可以建立线段树维护区间gcd,对于单点的值用树状数组维护即可。

    注意查询时,如果l==r就直接给出a[l]的值即可,或者在线段树查询时特判返回0,注意取abs

    修改时如果r==n就不改r+1了

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    int n,m,root,num;
    int a[maxn],b[maxn];
    int ls[maxn<<1],rs[maxn<<1],gcd[maxn<<1];
    int cx[maxn];
    
    template<class T>inline void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    int get_gcd(int a,int b){
        return !b ? a : get_gcd(b,a%b);
    }
    
    void update(int rt){
        gcd[rt]=get_gcd(gcd[ls[rt]],gcd[rs[rt]]);
    }
    
    void build(int &rt,int l,int r){
        if(!rt) rt=++num;
        if(l==r) {gcd[rt]=a[l];return ;}
        int mid=(l+r)>>1;
        build(ls[rt],l,mid);
        build(rs[rt],mid+1,r);
        update(rt);
    }
    
    void add(int x,int val){for(;x<=n;x+=x&-x) cx[x]+=val;}
    
    int sum(int x){
        int ret=0;
        for(;x;x-=x&-x)
         ret+=cx[x];
        return ret;
    }
    
    int query(int rt,int l,int r,int L,int R){
        if(L<=l&&r<=R) return gcd[rt];
        int mid=(l+r)>>1;
        if(R<=mid) return query(ls[rt],l,mid,L,R);
        if(mid<L) return query(rs[rt],mid+1,r,L,R);
        return get_gcd(query(ls[rt],l,mid,L,R),query(rs[rt],mid+1,r,L,R));
    }
    
    void modify(int rt,int l,int r,int pos,int val){
        if(l==r){
            gcd[rt]+=val;
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) modify(ls[rt],l,mid,pos,val);
        else modify(rs[rt],mid+1,r,pos,val);
        update(rt);
    }
    
    int main(){
        read(n);read(m);
        for(int i=1;i<=n;i++)read(a[i]);
        for(int i=n;i;i--) a[i]-=a[i-1],add(i,a[i]);
        build(root,1,n);
        for(int i=1;i<=m;i++){
            int op,l,r;
            read(op);read(l);read(r);
            if(l>r) swap(l,r);
            if(op==1){
                if(l==r) printf("%d
    ",sum(l));
                else printf("%d
    ",abs(get_gcd(sum(l),query(root,1,n,l+1,r))));
            }
            else {
                int v;
                read(v);
                add(l,v);add(r+1,-v);
                modify(root,1,n,l,v);
                if(r<n) modify(root,1,n,r+1,-v);
            }
        }
    }
    View Code
  • 相关阅读:
    机器学习(3)- 学习建议<误差出现如何解决?>
    机器学习(2)- 神经网络
    推荐系统(2)
    机器学习(1)- 概述&线性回归&逻辑回归&正则化
    朴素贝叶斯法(naive Bayes)
    约瑟夫环(java)
    AJAX请求详解 同步异步 GET和POST
    AJAX
    JspWriter与PrintWriter(转)
    Jsunit
  • 原文地址:https://www.cnblogs.com/sto324/p/11240530.html
Copyright © 2011-2022 走看看