zoukankan      html  css  js  c++  java
  • bzoj 5028: 小Z的加油店——带修改的区间gcd

    Description

    小Z经营一家加油店。小Z加油的方式非常奇怪。他有一排瓶子,每个瓶子有一个容量vi。每次别人来加油,他会让
    别人选连续一段的瓶子。他可以用这些瓶子装汽油,但他只有三种操作:
    1.把一个瓶子完全加满;
    2.把一个瓶子完全倒空;
    3.把一个瓶子里的汽油倒进另一个瓶子,直到倒出瓶子空了或者倒进的瓶子满了。
    当然,为了回馈用户,小Z会时不时选择连续一段瓶子,给每个瓶子容积都增加x。
    为了尽可能给更多的人加油,每次客户来加油他都想知道他能够倒腾出的汽油量最少是多少?
    当然他不会一点汽油都不给客户。

    Input

    第一行包括两个数字:瓶子数n,事件数m。
    第二行包含n个整数,表示每个瓶子的容量vi。
    接下来m行,每行先有三个整数fi li ri。
    若fi=1表示询问li到ri他最少能倒腾出的汽油量最少是多少?
    若fi=2 再读入一个整数x。表示他将li到ri的瓶子容量都增加了x。
    1 <= n,m <= 10^5 , 1<=li<=ri<=n , 1<=初始容量,增加的容量<=1000

    Output

    对于每个询问输出对应的答案

    Sample Input

    3 4
    2 3 4
    1 1 3
    2 2 2 1
    1 1 3
    1 2 3

    Sample Output

    1
    2
    4

    HINT

     有可能出现L>R

    ——————————————————————————————

    考虑一下更相减损术 题目就转换成了求区间gcd(带修改

    这是一波套路题 考虑gcd(a,b,c,d,e)=gcd(a-b,b-c,c-d,d-e,e)

    所以我们可以维护一下差分 也就是类似a-b这样的东西

    这样之后区间l->r +v 就变成了 l-1 - v  r +v

    当然注意最后的e是不带差分的 所以还要维护一下原序列 方便查询右端点r

    所以需要的操作就是 维护原序列的差分(单点修改区间查gcd)和原序列本身(区间加单点查询)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int M=1e5+7;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    } 
    int n,m,p;
    int N,g[3*M],bit[M],h[M];
    int gcd(int x,int y){
        while(y){p=x%y; x=y; y=p;}
        return x;
    }
    void tr_modify(int x,int v){
        g[x+=N]+=v;
        for(x>>=1;x;x>>=1) g[x]=gcd(g[x<<1],g[x<<1^1]);
    }
    #define lowbit(x) x&-x
    int s[M];
    void bit_insert(int x,int v){
        while(x<=n){
            s[x]+=v; 
            x+=lowbit(x);
        }
    }
    int bit_query(int x){
        int ans=h[x];
        while(x) ans+=s[x],x-=lowbit(x);
        return ans;
    }
    void modify(int l,int r,int v){
        bit_insert(l,v); tr_modify(l-1,-v);
        bit_insert(r+1,-v); tr_modify(r,v);
    }
    int push_ans(int l,int r){
        int ans=bit_query(r);
        for(l=l+N-1,r=r+N;r-l!=1;l>>=1,r>>=1){
            if(~l&1) ans=gcd(ans,g[l^1]);
            if(r&1) ans=gcd(ans,g[r^1]);
        }
        if(ans<0) ans=-ans;
        return ans;
    }
    void pd(int &x,int &y){if(x>y) std::swap(x,y);}
    int main(){
        int k,l,r,v;
        n=read(); m=read();
        for(int i=1;i<=n;i++) h[i]=read();
        for(N=1;N<=n+5;N<<=1);
        for(int i=1;i<n;i++) g[i+N]=h[i]-h[i+1];
        for(int i=N-1;i;i--) g[i]=gcd(g[i<<1],g[i<<1^1]);
        for(int i=1;i<=m;i++){
            k=read(); 
            if(k==1) l=read(),r=read(),pd(l,r),printf("%d
    ",push_ans(l,r));
            else l=read(),r=read(),v=read(),pd(l,r),modify(l,r,v);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    linux中grep用法(“或”、“与”)
    mac 常用开发软件列表
    Devops实战(四)Rancher的部署与安装详解
    Devops实战(三)Kubenets与minikube的安装以及使用实战
    intel 无线网卡 AC8260 周期性跳ping(高延迟)解决方案
    确定了,回归吧,19,20就当换了换环境,该努力了。
    win10下用Linux搭建python&nodejs开发环境
    pict总结
    移动无线常用测试工具
    游戏测试工具
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7500792.html
Copyright © 2011-2022 走看看