火车载客(ybtoj-二叉堆)

10 篇文章 0 订阅

题目描述

在这里插入图片描述

解析

我的思路

其实就是线段覆盖的一个变体
贪心的想:
把游客按右端点升序排序
后面的证明就和线段覆盖一样了
如果有两个游客冲突
我们应该选右端点靠右的
因为这样对以后继续在右边出现的游客来说肯定不会更差

然后就是对于能否上车的判断
其实就是一个对区间的修改与最大值查询
就非常自然的想到了线段树

时间复杂度:nlogn

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5+100;
ll ans;
int n,c,k;

#define mid ((r+l)>>1)
int mx[4*N],add[4*N];
void Add(int k,int v){
	add[k]+=v;
	mx[k]+=v;
	return;
}
void pushdown(int k){
	if(add[k]==0) return;
	Add(k<<1,add[k]);
	Add(k<<1|1,add[k]);
	add[k]=0; 
}
void change(int k,int l,int r,int x,int y,int v){
//	printf("l=%d r=%d x=%d y=%d\n",l,r,x,y);
	if(x<=l&&r<=y){
		Add(k,v);
		return;
	}
	pushdown(k);
	if(x<=mid) change(k<<1,l,mid,x,y,v);
	if(y>=mid+1) change(k<<1|1,mid+1,r,x,y,v);
	mx[k]=max(mx[k<<1],mx[k<<1|1]);
	return;
}
int ask(int k,int l,int r,int x,int y){
//	printf("l=%d r=%d x=%d y=%d\n",l,r,x,y);
	if(x<=l&&r<=y){
//		printf("l=%d r=%d res=%d\n",l,r,mx[k]);
		return mx[k];
	}
	pushdown(k);
	int res=0;
	if(x<=mid) res=max(res,ask(k<<1,l,mid,x,y));
	if(y>=mid+1) res=max(res,ask(k<<1|1,mid+1,r,x,y));
//	printf("l=%d r=%d res=%d\n",l,r,res);
	mx[k]=max(mx[k<<1],mx[k<<1|1]);
	return res;
}

struct node{
	int x,y,num;
	bool operator < (const node o)const{return y<o.y;} 
}p[N];
int main(){
	scanf("%d%d%d",&k,&n,&c);
	for(int i=1;i<=k;i++){
		scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].num);
	}		
	sort(p+1,p+1+k);
	for(int i=1;i<=k;i++){
		int xx=p[i].x,yy=p[i].y,nn=p[i].num;
		int ad=min(nn,c-ask(1,1,n,xx,yy-1));
//		printf("i=%d ad=%d ask=%d\n",i,ad,ask(1,1,n,xx,yy));
//		printf("x=%d y=%d ad=%d\n\n",xx,yy-1,ad);
		ans+=ad;
		change(1,1,n,xx,yy-1,ad);
	}
	printf("%lld",ans);
}
/*
in:
8 15 3
1 5 2
13 14 1
5 8 3
8 14 2
14 15 1
9 12 1
12 15 2
4 6 1
out:10
*/

题解思路

突然想到这道二叉堆的题自己似乎并没有用到二叉堆。。。
于是又看了下题解

大概思路就是:
每到一站,只要没满就让游客上来
如果满了,就强制让目的地最靠后的游客下车
当然,已经到站的下车就行(在这个策略下到站的已经就是堆顶元素)
对于那些没到站就被迫下车的游客,等价于没有让他们上车

这样就不用写线段树了,码量减少许多;而且思路也很妙

小技巧:对于一些由于后续情况而当前不知道是否选择的决策,可以暂时先选上,与更优决策与它冲突时再放弃,这样也就等价与没有选择

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值