• 【雅礼集训 2017 Day1】市场


    题面

    20171128201915_68999

    分析

    区间加很裸

    关键是怎么处理除的问题,很明显,不能用lazy,因为不能满足直接合并左右区间而得到大区间的答案

    除的效果是会让数字变小,那么减法也可以做到,我们就把除法变成减法

    当序列被除到一个比较小的数的时候,最后减去的数可以是相同的

    比如 2 2  2 3 除以3,得到 0 0 0 1,相当于每个数减去了2.只需要维护序列中最大的数除后等效的减的值和最小的数除后等效减的值,如果一样,就进行区间减,修改lazy。

    此题的坑点在于有负数,负数除法要手动向下取整

    听起来挺暴力的,时间复杂度的证明不会,据说是均摊时间复杂度?

    #include<bits/stdc++.h>
    using namespace std;
    #define N 201000 
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define INF 0x7fffffff7fffffff
    #define mid (t[p].l+t[p].r>>1)
    #define INT int
    #define ll long long 
    
    ll n,q; 
    ll a[N];
    struct email
    {
        ll l,r,minx,maxx,sum,lazy;
    }t[N*4];
    
    inline ll divid(ll x,ll y) 
    {
        return floor((double)x/y);
    }
    
    void pushnow(ll p,ll v)
    {
        t[p].lazy+=v;
        t[p].sum+=v*(t[p].r-t[p].l+1);
        t[p].maxx+=v;
        t[p].minx+=v;
    }
    void pushup(ll p)
    {
        t[p].maxx=max(t[lc].maxx,t[rc].maxx);
        t[p].minx=min(t[lc].minx,t[rc].minx);
        t[p].sum=t[lc].sum+t[rc].sum;
    }
    
    void pushdown(ll p)
    {
        if(t[p].lazy)
        {
            pushnow(lc,t[p].lazy);
            pushnow(rc,t[p].lazy);
            t[p].lazy=0;
        }
     } 
     
    void build(ll p,ll l,ll r)
    {
        t[p].l=l,t[p].r=r;
        if(l==r)
        {
            t[p].lazy=0;
            t[p].sum=a[l];
            t[p].minx=a[l];
            t[p].maxx=a[l];
            return ;
        }
        ll m=(l+r)>>1;
        build(lc,l,m);build(rc,m+1,r);
        pushup(p);
    }
    
    void update(ll p,ll ql,ll qr,ll v)
    {
        if(ql<=t[p].l&&qr>=t[p].r)
        {
            pushnow(p,v);
            return ;
        }
        pushdown(p);
        if(ql<=mid)update(lc,ql,qr,v);
        if(qr>mid)update(rc,ql,qr,v);
        pushup(p);
    }
    ll query_min(ll p,ll ql,ll qr)
    {
        ll ans=INF;
        if(ql<=t[p].l&&qr>=t[p].r)
            return t[p].minx;
        pushdown(p);
        if(ql<=mid)ans=min(ans,query_min(lc,ql,qr));
        if(qr>mid)ans=min(ans,query_min(rc,ql,qr));
        pushup(p);
        return ans;
    }
    
    ll query_sum(ll p,ll ql,ll qr)
    {
        ll ans=0;
        if(ql<=t[p].l&&qr>=t[p].r)
            return t[p].sum;
        pushdown(p);
        if(ql<=mid)ans+=query_sum(lc,ql,qr);
        if(qr>mid)ans+=query_sum(rc,ql,qr);
        pushup(p);
        return ans;
    }
    
    void divide(ll p,ll ql,ll qr,ll v)
    {
        if(ql<=t[p].l&&qr>=t[p].r)
        {
            ll delta1=t[p].maxx;delta1=delta1-divid(delta1,v);
            ll delta2=t[p].minx;delta2=delta2-divid(delta2,v);
            if(delta1==delta2)
            {
                pushnow(p,-delta1);
                return ;    
            }
        }
        pushdown(p);
        if(ql<=mid)divide(lc,ql,qr,v);
        if(qr>mid)divide(rc,ql,qr,v);
        pushup(p);
    }
    
    INT main()
    {
            scanf("%lld%lld",&n,&q);
        for(ll i=0;i<n;i++)
            scanf("%lld",&a[i]);
        build(1,0,n-1);
        while(q--)
        {
            ll op;
            scanf("%lld",&op);
            if(op==1)
            {
                ll l,r,c;
                scanf("%lld%lld%lld",&l,&r,&c);
                update(1,l,r,c);
            }
            if(op==2)
            {
                ll l,r,c;
                scanf("%lld%lld%lld",&l,&r,&c);
                divide(1,l,r,c);        
            }
            if(op==3)
            {
                ll l,r;
                scanf("%lld%lld",&l,&r);
                printf("%lld
    ",query_min(1,l,r));
            }
            if(op==4)
            {
                ll l,r;
                scanf("%lld%lld",&l,&r);
                printf("%lld
    ",query_sum(1,l,r));
            }    
        }
        return 0;
    }    
    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    Java知识积累3-XML的DOM解析修改和删除方法
    Java知识积累-XML的DOM解析修改和删除方法
    Java知识积累2-StringReverse实现文字(单词)倒叙输出
    Java知识积累1-StringAlign实现文字居中左右对齐
    String中具有的方法
    有17个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下 的是原来第几号的那位
    编写一个程序,求出整数数组中最小元素的下标。如果这样的元素个数大于1,则返回下标最小的数的下标。
    初识
    关于点击跳转页面
    sql存储过程
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9452340.html
Copyright © 2020-2023  润新知