• bzoj 5321(二分+优先队列+线段树)


    传送门

    题意:

    给你一个长度为nn的数组, 以及mm个连续的区间。现在让你取恰好kk个区间,你要将你选取的kk个区间都加上aa。现在要你最大化整个数组的最小值,即要最大化min{Ai}min { A_i }

    题解:

    最大化最小值,看到这样的词汇就非常二分了,于是乎我们就考虑采用二分答案解决。

    于是乎,我们现在需要考虑的就是如何进行check ext{check}

    我们首先考虑哪些如何选取这kk个区间才能使得我们的结果最优。一个贪心的选法就是,选择的区间一定要覆盖最小值的区间,同时区间的大小要尽可能的大。

    因此我们可以考虑先将区间根据左端点的大小排序,然后当我们二分出一个答案mid ext{mid}的时候,我们先遍历整个数组,而在遍历的过程中,我们把能够包涵该端点的所有区间(即l<il<i)都压入一个容器中。而若当前的位置的值小于我们所二分的答案mid ext{mid},则我们考虑使用容器中的区间进行更新。而根据我们之前所说的贪心的选法,我们明显需要优先选取右端点距离远的区间,因此我们此时我们只需要用一个优先队列对符合条件的区间进行维护即可。

    最后,倘若我们发现没有符合条件的区间,亦或者我们选取的区间个数大于kk,则证明当前二分值mid ext{mid}过大,此时我们只需要将rr左移即可。

    最后,上述算法也仅涉及区间更新以及单调查询,因此我们可以用线段树或者差分树状数组进行维护。整体的时间复杂度为:O(nlog2n)mathcal{O}(nlog^2n)

    代码:

    • 线段树版本:
    #include <bits/stdc++.h>
    #define maxn 200005
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pll;
    struct ST{
        ll sum,lazy;
        int len;
    }tr[maxn<<2];
    int A[maxn];
    void push_up(int rt){
        tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
    }
    void push_down(int rt){
        if(tr[rt].lazy){
            tr[rt<<1].sum+=tr[rt].lazy*tr[rt<<1].len;
            tr[rt<<1|1].sum+=tr[rt].lazy*tr[rt<<1|1].len;
            tr[rt<<1].lazy+=tr[rt].lazy;
            tr[rt<<1|1].lazy+=tr[rt].lazy;
            tr[rt].lazy=0;
        }
    }
    void build(int l,int r,int rt){
        tr[rt].len=r-l+1;
        tr[rt].lazy=0;
        if(l==r){
            tr[rt].sum=A[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        push_up(rt);
    }
    void update(int L,int R,int l,int r,int rt,int C){
        if(L<=l&&R>=r){
            tr[rt].lazy+=C;
            tr[rt].sum+=C*tr[rt].len;
            return ;
        }
        int mid=(l+r)>>1;
        push_down(rt);
        if(L<=mid) update(L,R,l,mid,rt<<1,C);
        if(R>mid) update(L,R,mid+1,r,rt<<1|1,C);
        push_up(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l&&R>=r){
            return tr[rt].sum;
        }
        int mid=(l+r)>>1;
        push_down(rt);
        ll res=0;
        if(L<=mid) res+=query(L,R,l,mid,rt<<1);
        if(R>mid) res+=query(L,R,mid+1,r,rt<<1|1);
        return res;
    }
    priority_queue<pll>que;
    pll q[maxn];
    int n,m,k,a;
    bool judge(ll x){
        build(1,n,1);
        while(!que.empty()) que.pop();
        int cnt=1;
        int tt=0;
        for(int i=1;i<=n;i++){
            while(cnt<=m&&q[cnt].first<=i){
                que.push(pll(q[cnt].second,q[cnt].first));
                cnt++;
            }
            while(query(i,i,1,n,1)<x){
                if(que.empty()) return false;
                pll p=que.top();
                que.pop();
                if(p.first<i) return false;
                int l=p.second,r=p.first;
                //cout<<"// "<<l<<" "<<r<<endl;
                update(l,r,1,n,1,a);
                tt++;
                if(tt>k) return false;
            }
        }
        return true;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d%d",&n,&m,&k,&a);
            int minn=0x3f3f3f3f;
            for(int i=1;i<=n;i++){
                scanf("%d",&A[i]);
                minn=min(minn,A[i]);
            }
            for(int i=1;i<=m;i++){
                scanf("%d%d",&q[i].first,&q[i].second);
            }
            sort(q+1,q+1+m);
            ll l=minn,r=minn+k*a;
            while(l<r){
                ll mid=(l+r)>>1;
                //cout<<l<<" "<<r<<" "<<mid<<endl;
                if(judge(mid)) l=mid+1;
                else r=mid;
            }
            if(judge(l)) printf("%lld
    ",l);
            else printf("%lld
    ",l-1);
        }
    }
    
    • 差分树状数组:
    #include <bits/stdc++.h>
    #define maxn 200005
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pll;
    int A[maxn];
    ll bit[maxn<<1];
    priority_queue<pll>que;
    pll q[maxn];
    ll lowbit(ll x){
        return x&-x;
    }
    void update(int pos,ll C){
        while(pos<maxn){
            bit[pos]+=C;
            pos+=lowbit(pos);
        }
    }
    ll query(int pos){
        ll res=0;
        while(pos){
            res+=bit[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    int n,m,k,a;
    bool judge(ll x){
        memset(bit,0,sizeof(ll)*(n+3));
        while(!que.empty()) que.pop();
        int cnt=1;
        int tt=0;
        for(int i=1;i<=n;i++){
            update(i,A[i]);
            update(i+1,-A[i]);
        }
        for(int i=1;i<=n;i++){
            while(cnt<=m&&q[cnt].first<=i){
                que.push(pll(q[cnt].second,q[cnt].first));
                cnt++;
            }
            while(query(i)<x){
                if(que.empty()) return false;
                pll p=que.top();
                que.pop();
                if(p.first<i) return false;
                int l=p.second,r=p.first;
                update(l,a);
                update(r+1,-a);
                tt++;
                if(tt>k) return false;
            }
        }
        return true;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d%d",&n,&m,&k,&a);
            int minn=0x3f3f3f3f;
            for(int i=1;i<=n;i++){
                scanf("%d",&A[i]);
                minn=min(minn,A[i]);
            }
            for(int i=1;i<=m;i++){
                scanf("%d%d",&q[i].first,&q[i].second);
            }
            sort(q+1,q+1+m);
            ll l=minn,r=minn+k*a;
            while(l<r){
                ll mid=(l+r)>>1;
                if(judge(mid)) l=mid+1;
                else r=mid;
            }
            if(judge(l)) printf("%lld
    ",l);
            else printf("%lld
    ",l-1);
        }
    }
    
  • 相关阅读:
    算法疑难(js实现)---5、变态跳台阶
    算法疑难(js实现)---4、跳台阶(记忆化递归)
    算法疑难(js实现)---3、两个栈来实现一个队列
    算法疑难(js实现)---2、重建二叉树
    Ext的Panel总结(好文章)
    Extjs datefield 日历控件中文显示
    EXTJS项目实战经验总结一:日期组件的change事件:
    ExtJs内的datefield控件选择日期过后的事件监听select
    ExtJs FormPanel布局
    开发extjs常用的插件
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007152.html
Copyright © 2020-2023  润新知