BZOJ1577: [Usaco2009 Feb]庙会捷运Fair Shuttle 贪心+线段树

1577: [Usaco2009 Feb]庙会捷运Fair Shuttle

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 310   Solved: 171

Description

公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N。K(1<=K<=50000)群奶牛希望搭乘这辆公交车。第i群牛一共有Mi(1<=Mi<=N)只.

他们希望从Si到Ei去。
公交车只能座C(1<=C<=100)只奶牛。而且不走重复路线,请计算这辆车最多能满足多少奶牛听要求。
注意:对于每一群奶牛,可以部分满足,也可以全部满足,也可以全部不满足。

Input

第1行: 三个整数: K,N,C。 由空格隔开。

第2..K+1行:第i+1行,告诉你第i组奶牛的信息: S_i, E_i and M_i。由空格隔开。

Output

一行:可以在庙会乘坐捷运的牛的最大头数

Sample Input

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

Sample Output

10

HINT

捷运可以把2头奶牛从展台1送到展台5,3头奶牛从展台5到展台8, 2头奶牛从展台8 到展台14,1头奶牛从展台9送到展台12,一头奶牛从展台13送到展台14, 一头奶牛从 14送到15。

题解:
先贪心:
把询问按照右端点的大小递增排序,然后右端点相同时,左端点较大的在前
然后上线段树:
对于每一个区间,查询最小值,在最小值和该团队的牛的数量取一个min,之后把区间减去min,也就是上尽可能多的牛
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
struct pp {int l,r,w;} Q[N];
struct Tree{int l,r,mn,lazy;}T[N*4];
int n,l,c,ans;
bool cmp(pp u,pp v)
{
	if(u.r!=v.r) return u.r<v.r;
	return u.l>v.l;
}
void pushup(int x)
{
	T[x].mn=min(T[x<<1].mn,T[x<<1|1].mn);
}
void build(int x,int l,int r)
{
	T[x].l=l,T[x].r=r;
	T[x].mn=c;
	if(l==r) return;
	int mid=(T[x].l+T[x].r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
void pushdown(int x)
{
	int lc=x<<1,rc=x<<1|1;
	T[lc].mn+=T[x].lazy;
	T[rc].mn+=T[x].lazy;
	T[lc].lazy+=T[x].lazy;
	T[rc].lazy+=T[x].lazy;
	T[x].lazy=0;
}
int Query(int x,int l,int r)
{
	if(T[x].l==l&&T[x].r==r) return T[x].mn;
	if(T[x].lazy) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) return Query(x<<1,l,r);
	else if(l>mid) return Query(x<<1|1,l,r);
	else return min(Query(x<<1,l,mid),Query(x<<1|1,mid+1,r));
}
void Modify(int x,int l,int r,int v)
{
	if(T[x].l==l&&T[x].r==r)
	{
		T[x].mn+=v;
		T[x].lazy+=v;
		return;
	}
	if(T[x].lazy) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) Modify(x<<1,l,r,v);
	else if(l>mid) Modify(x<<1|1,l,r,v);
	else Modify(x<<1,l,mid,v),Modify(x<<1|1,mid+1,r,v);
	pushup(x);
}
int main()
{
	scanf("%d%d%d",&n,&l,&c);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].w);
		Q[i].r--;
	}
	sort(Q+1,Q+n+1,cmp);
	build(1,1,l);
	for(int i=1;i<=n;i++)
	{
		int x=Q[i].l,y=Q[i].r;
		int tmp=min(Q[i].w,Query(1,x,y));
		if(tmp)
		{
			ans+=tmp;
			Modify(1,x,y,-tmp);
		}
	}
	printf("%d",ans);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值