观光公交——堆优化

题意:2011noip原题,不再赘述。

之前贪心的做法固然是正确的。但一个一个加速器用显得太慢了,能不能一次性使用多个加速器呢?
答案完全是可以的,同之前贪心策略类似的,关注每站的T_up_max和T_down_max,以及每站的下车人数,并将其前缀和维护。 那么就找max(T_down_max-T_up_max),即使用加速器的个数。

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) 
#define LL long long 
#define INF 0x3f3f3f3f
#define N 1005
#define M 10005
#define S 100005
using namespace std;
int n,m,k;
int ans;
int dis[N];
int down[M],up[M];
int sum[N],g[N];
struct node{
    int t,s,e;
}A[M];
struct Node{
    int L,R;
    bool operator<(const Node &a)const{
        return sum[R]-sum[L]<sum[a.R]-sum[a.L]; 
    }
};
priority_queue<Node>Q;

void Init(){
    REP(i,1,m)sum[A[i].e]++,up[A[i].s]=max(up[A[i].s],A[i].t);
    REP(i,1,n)down[i]=max(down[i-1],up[i-1])+dis[i-1];
    REP(i,1,n)sum[i]+=sum[i-1];
    REP(i,1,m)ans+=down[A[i].e]-A[i].t;
}   
void solve(){
    Q.push((Node){1,n});
    while(!Q.empty()&&k){
        int l=Q.top().L,r=Q.top().R;
        Q.pop();
        int Mx=min(k,dis[l]),pos=-1;
        REP(i,l+1,r-1)if(down[i]-up[i]<Mx)Mx=down[i]-up[i],pos=i;
        if(Mx>0){
            k-=Mx;
            ans-=(sum[r]-sum[l])*Mx;
            dis[l]-=Mx;
            REP(i,1,n)down[i]=max(down[i-1],up[i-1])+dis[i-1];
        }
        if(pos!=-1){
            if(l<pos)Q.push((Node){l,pos});
            if(pos<r)Q.push((Node){pos,r});
        }
        else if(l+1<r)Q.push((Node){l+1,r});
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    REP(i,1,n-1)scanf("%d",&dis[i]);
    REP(i,1,m)scanf("%d%d%d",&A[i].t,&A[i].s,&A[i].e);
    Init();
    solve();
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值