zoukankan      html  css  js  c++  java
  • 「雅礼集训 2017 Day1」市场 (线段树除法,区间最小,区间查询)

    老师说,你们暴力求除法也整不了多少次就归一了,暴力就好了(应该只有log(n)次)
    于是暴力啊暴力,结果我归天了。
    好吧,在各种题解的摧残下,我终于出了一篇巨好看(chou lou)代码(很多结构体党嫌丑)
    #题意
    那么具体除法怎么实现就是关键了
    对于单个点或者区间内的数完全相同的区间,可以做成区间减法
    因为除法会使数变小,而相同的数减小的量是相同的,

    那么怎么判断区间内的数是否完全相同呢?

    可以维护一个区间最小与区间最大,如果一个区间内最小数等于最大数,那么显然这个区间内所有数相等
    区间最小与区间最大就不用说了吧?
    然后暴力一波

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll sum[400101]={0}, minn[400101],maxx[400001]={0},add[400101]={0},a[401001];
    int n,m;
    void pushup(ll rt){
        sum[rt]=sum[rt<<1|1]+sum[rt<<1];
        minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
        maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
    }
    inline ll Div(ll x, ll y) {//从样例分析出这道题是向下取整的除法
        return floor((double)x/y);
    }
    void build(ll l,ll r,ll rt){
        if(l==r){
            sum[rt]=a[l];
            minn[rt]=a[l];
            maxx[rt]=a[l];
            return ;
        }
        long long mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        pushup(rt);
    }
    void pushdown(ll rt,ll ln,ll rn){
        if(add[rt]!=0){
            add[rt<<1]+=add[rt];
            add[rt<<1|1]+=add[rt];
            sum[rt<<1]+=add[rt]*ln;
            sum[rt<<1|1]+=add[rt]*rn;
            minn[rt<<1]+=add[rt];
            minn[rt<<1|1]+=add[rt];
            maxx[rt<<1]+=add[rt];
            maxx[rt<<1|1]+=add[rt];
            add[rt]=0;
        }
    }
    void update1(ll l,ll r,ll c,ll L,ll R,ll rt){
        if(l>=L&&r<=R){
            sum[rt]+=c*(r-l+1);
            add[rt]+=c;minn[rt]+=c;maxx[rt]+=c;
            return ;
        }
        ll mid=(l+r)>>1;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid)update1(l,mid,c,L,R,rt<<1);
        if(R>mid)update1(mid+1,r,c,L,R,rt<<1|1);
        pushup(rt);
    }
    void update2(ll l,ll r,ll c,ll L,ll R,ll rt){//对于除法的暴力操作
         if (l >=L&&r<=R&&maxx[rt]-Div(maxx[rt],c)==minn[rt]-Div(minn[rt],c)){
            ll D=Div(maxx[rt],c)-maxx[rt];
            add[rt]+=D;maxx[rt]+=D;minn[rt]+=D;
            sum[rt]+=D*(r-l+1);
            return;
        }
        ll mid=(l+r)>>1;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid)update2(l,mid,c,L,R,rt<<1);
        if(mid<R)update2(mid+1,r,c,L,R,rt<<1|1);
        pushup(rt);
    }
    ll query1(ll l,ll r,ll L,ll R,ll rt){
        if(l>=L&&r<=R){
            return sum[rt];
        }
        ll mid=(l+r)>>1;
        ll ans=0;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid)ans+=query1(l,mid,L,R,rt<<1);
        if(R>mid)ans+=query1(mid+1,r,L,R,rt<<1|1);
        return ans;
    }
    ll query2(ll l,ll r,ll L,ll R,ll rt){
        if(l>=L&&r<=R){
            return minn[rt];
        }
        ll mid=(l+r)>>1;
        ll ans=1e18;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid)ans=min(ans,query2(l,mid,L,R,rt<<1));
        if(R>mid)ans=min(ans,query2(mid+1,r,L,R,rt<<1|1));
        return ans;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%lld",&a[i]);
        //memset(flag,1,sizeof(flag));
        build(0,n-1,1);
        while(m--){
            long long c,x,y,k;
            scanf("%lld%lld%lld",&c,&x,&y);
            if(c==1){scanf("%lld",&k);update1(0,n-1,k,x,y,1);}
            if(c==2){scanf("%lld",&k);update2(0,n-1,k,x,y,1);}
            if(c==4)printf("%lld
    ",query1(0,n-1,x,y,1));
            if(c==3)printf("%lld
    ",query2(0,n-1,x,y,1));
        }
        return 0;
    }
  • 相关阅读:
    linux 图片压缩
    (四)基于商品属性的相似商品推荐算法——推荐与评分高的商品属性相似的商品
    (三)基于商品属性的相似商品推荐算法——批量处理商品属性,得到属性前缀及完整属性字符串
    老王为测量初学者准备的测量宝典
    全站仪 经纬仪 水准仪 操作演示视频教程 建筑工程测量放线7日通
    【地铁测量-车站】02 车站模板抄平思路
    【地铁测量-车站】01 模板放样正反算妙用
    手机操控全站仪安卓版 测量员.app
    【卡西欧Fx-5800p】市场分析 ppt
    【卡西欧Fx5800-p程序】01 坐标转换程序-带注释
  • 原文地址:https://www.cnblogs.com/lisuier/p/9535093.html
Copyright © 2011-2022 走看看