2018.09.24 bzoj4977: [[Lydsy1708月赛]跳伞求生(贪心+线段树)

时间:2023-03-08 23:25:41
2018.09.24 bzoj4977: [[Lydsy1708月赛]跳伞求生(贪心+线段树)

传送门

线段树好题。

这题一看我就想贪心。

先把a,b数组排序。

然后我们选择a数组中最大的b个数(不足b个就选a个数),分别贪心出在b数组中可以获得的最大贡献。

这时可以用线段树优化。

然后交上去只能过一个点(雾

调了很久都没有发现错误点。

于是搜题解。

发现大家的做法都跟我不一样233。

但我不能放弃。

就在这时我发现有可能每次贪心出的最大贡献可能是负数233。

于是我们把每次的决策都记下来。

最后枚举删去最小的决策(有可能是负数,这样答案会增加)之后的贡献来更新答案。

代码:

#include<bits/stdc++.h>
#define N 100005
#define ll long long
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int n,m,top;
bool vis[N];
ll ans=0,sum=0,val[N],a[N],s1[N],s2[N];
struct node{int v;ll w;}q[N];
struct Node{int l,r;ll mx;}T[N<<2];
inline bool cmp(node a,node b){return a.v<b.v;}
inline ll max(ll a,ll b){return a>b?a:b;}
inline void pushup(int p){T[p].mx=max(T[lc].mx,T[rc].mx);}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r;
    if(l==r){T[p].mx=q[l].w;return;}
    build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int k){
    if(T[p].l==T[p].r){T[p].mx=-0x3f3f3f3f;return;}
    if(k<=mid)update(lc,k);
    else update(rc,k);
    pushup(p);
}
inline int ask(int p){
    if(T[p].l==T[p].r)return T[p].l;
    if(T[lc].mx==T[p].mx)return ask(lc);
    return ask(rc);
}
inline int query(int p,int ql,int qr){
    if(ql<=T[p].l&&T[p].r<=qr)return ask(p);
    if(qr<=mid)return query(lc,ql,qr);
    if(ql>mid)return query(rc,ql,qr);
    int L=query(lc,ql,mid),R=query(rc,mid+1,qr);
    return q[L].w>=q[R].w?L:R;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i)a[i]=read();
    sort(a+1,a+n+1);
    for(int i=1;i<=m;++i)q[i].v=read(),q[i].w=read()-q[i].v;
    sort(q+1,q+m+1,cmp),build(1,1,m);
    for(int i=1;i<=m;++i)val[i]=q[i].v;
    int up=max(1,n-m+1);
    for(int i=up;i<=n;++i){
        int pos=lower_bound(val+1,val+m+1,a[i])-val;
        if(a[i]<=val[pos])--pos;
        if(pos<=0)continue;
        ll tmp=query(1,1,pos);
        update(1,tmp),sum+=a[i]+q[tmp].w,s1[++top]=a[i],s2[top]=q[tmp].w,q[tmp].w=-0x3f3f3f3f;
    }
    ans=sum,sort(s1+1,s1+top+1),sort(s2+1,s2+top+1);
    for(int i=1;i<=top;++i)ans=max(ans,(sum-=s1[i]+s2[i]));
    cout<<ans;
    return 0;
}