线段树【p1607】[USACO09FEB]庙会班车Fair Shuttle

Description

逛逛集市,兑兑奖品,看看节目对农夫约翰来说不算什么,可是他的奶牛们非常缺乏锻炼——如果要逛完一整天的集市,他们一定会筋疲力尽的。所以为了让奶牛们也能愉快地逛集市,约翰准备让奶牛们在集市上以车代步。但是,约翰木有钱,他租来的班车只能在集市上沿直线跑一次,而且只能停靠N(1 ≤N≤20000)个地点(所有地点都以1到N之间的一个数字来表示)。现在奶牛们分成K(1≤K≤50000)个小组,第i 组有Mi(1 ≤Mi≤N)头奶牛,他们希望从Si跑到Ti(1 ≤Si<Ti≤N)。

由于班车容量有限,可能载不下所有想乘车的奶牛们,此时也允许小里的一部分奶牛分开乘坐班车。约翰经过调查得知班车的容量是C(1≤C≤100),请你帮助约翰计划一个尽可能满足更多奶牛愿望的方案。

Input

第一行:包括三个整数:K,N和C,彼此用空格隔开。

第二行到K+1行:在第i+1行,将会告诉你第i组奶牛的信息:Si,Ei和Mi,彼

Output

第一行:可以坐班车的奶牛的最大头数。

的确,这是一道线段树好题.

不过貌似正解是贪心.

算了,写了都写了,就来BB两句.

显然,这会是一个区间问题,而这个区间问题需要考虑的是当前这段区间内车的剩余容量.

明显的是,对于一段区间内车的剩余容量我们需要知道其最小的容量。才能知道能否继续有奶牛上车。

修改的时候的话,需要修改\([s_i,t_i-1]\)的区间最大值.

这就考虑成当前批次的奶牛会在\(t_i\)下车,又会有新的一批奶牛在\(t_i\)上车。

问题就是线段树维护动态区间最大值。(是叫这个吧 emm

代码

#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#define ls o<<1
#define rs o<<1|1
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m,c,tr[20008*8],tg[20008*8],ans;
struct cod{
    int s,t,m;
    bool operator <(const cod&a)
    const 
    {
        return t<a.t;
    }
}cow[200008];
inline void up(int o){tr[o]=max(tr[ls],tr[rs]);}
void build(int o,int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
inline void down(int o,int l,int r)
{
    if(tg[o])
    {
        tr[ls]+=tg[o],tr[rs]+=tg[o];
        tg[ls]+=tg[o],tg[rs]+=tg[o];
        tg[o]=0;
    }
}
void change(int o,int l,int r,int x,int y,int z)
{
    if(x<=l and y>=r)
    {
        tr[o]+=z;tg[o]+=z;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)change(ls,l,mid,x,y,z);
    if(y>mid) change(rs,mid+1,r,x,y,z);
    up(o);
}
int query(int o,int l,int r,int x,int y)
{
    if(x<=l and y>=r) return tr[o];
    down(o,l,r);
    int mid=(l+r)>>1,res=-214748364;
    if(x<=mid)res=max(res,query(ls,l,mid,x,y));
    if(y>mid)res=max(res,query(rs,mid+1,r,x,y));
    return res;
}
int main()
{
    in(m),in(n),in(c);
    for(R int i=1;i<=m;i++)
        in(cow[i].s),in(cow[i].t),in(cow[i].m);
    sort(cow+1,cow+m+1);
    build(1,1,n);
    for(R int i=1;i<=m;i++)
    {
        int now=query(1,1,n,cow[i].s,cow[i].t),res=0;
        if(now>=c)continue;
        if(now+cow[i].m<=c)res=cow[i].m;
        else res=c-now;
        ans+=res;
        change(1,1,n,cow[i].s,cow[i].t-1,res);
    }
    printf("%d",ans);
}

转载于:https://www.cnblogs.com/-guz/p/9776034.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值