P1607 [USACO09FEB]廟會班車Fair Shuttle(貪心+線段樹維護)

題目描述
Although Farmer John has no problems walking around the fair to collect prizes or see the shows, his cows are not in such good shape; a full day of walking around the fair leaves them exhausted. To help them enjoy the fair, FJ has arranged for a shuttle truck to take the cows from place to place in the fairgrounds.

FJ couldn’t afford a really great shuttle, so the shuttle he rented traverses its route only once (!) and makes N (1 <= N <= 20,000) stops (conveniently numbered 1…N) along its path. A total of K (1 <= K <= 50,000) groups of cows conveniently numbered 1…K wish to use the shuttle, each of the M_i (1 <= M_i <= N) cows in group i wanting to ride from one stop S_i (1 <= S_i < E_i) to another stop E_i (S_i < E_i <= N) farther along the route.

The shuttle might not be able to pick up an entire group of cows (since it has limited capacity) but can pick up partial groups as appropriate.

Given the capacity C (1 <= C <= 100) of the shuttle truck and the descriptions of the groups of cows that want to visit various sites at the fair, determine the maximum number of cows that can ride the shuttle during the fair.

逛逛集市,兌兌獎品,看看節目對農夫約翰來說不算什麼,可是他的奶牛們非常缺乏鍛鍊——如果要逛完一整天的集市,他們一定會筋疲力盡的。所以爲了讓奶牛們也能愉快地逛集市,約翰準備讓奶牛們在集市上以車代步。但是,約翰木有錢,他租來的班車只能在集市上沿直線跑一次,而且只能停靠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),請你幫助約翰計劃一個儘可能滿足更多奶牛願望的方案。

輸入格式
【輸入】

第一行:包括三個整數:K,N和C,彼此用空格隔開。

第二行到K+1行:在第i+1行,將會告訴你第i組奶牛的信息:Si,Ei和Mi,彼

此用空格隔開。

輸出格式
【輸出】

第一行:可以坐班車的奶牛的最大頭數。
輸入 #1
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
輸出 #1
10
【樣例說明】

班車可以把2頭奶牛從1送到5,3頭奶牛從5送到8,2頭奶牛從8送到14,1頭

奶牛從9送到12,1頭奶牛從13送到14,1頭奶牛從14送到15。

題意: 題意同會場安排問題很像,k組牛,每組牛都有想去的[ l , r ]區間,但不同的是車輛有載牛上限,所以需要知道某個區間內的牛數量的最大值,用線段樹來維護。注意每組牛可以只去一部分牛。
思路:

  1. 同會場安排的貪心方式,每組按右端點由小到大排序,右端點你相同則按左端點由小到大排序。
  2. 用線段樹維護區間最大值;注意維護時,將某組牛放到cnt車上時,不是區間的加,而是類似於區間加(具體看註釋),查到最大值res後,就只能再放入C-res個牛;
  3. 排序後遍歷一波,記錄即可。

ac代碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7;
const ll INF=1e9;
struct node
{
    ll l,r,v;
}stu[maxn];
ll sum[maxn*4],add[maxn*4];
bool cmp(node a,node b)
{
    if(a.r==b.r)    return a.l<b.l;
    return a.r<b.r;
}
void pushdown(ll root,ll k)
{
    if(add[root])
    {
        sum[root<<1]+=add[root];                ///不是區間求和操作,區間求和應爲sum[root<<1]+=(1-k>>1)*add[root],下行也需改
        sum[root<<1|1]+=add[root];
        add[root<<1]+=add[root];
        add[root<<1|1]+=add[root];
        add[root]=0;
    }
}
void change(ll root,ll l,ll r,ll ql,ll qr,ll k)
{
    if(ql<=l&&qr>=r)
    {
        sum[root]+=k;                   ///區間求和爲sum[root]+=(r-l)*k;這樣查詢時就能保證查到的是當前區間的最大值,否則查到的值會偏大。
        add[root]+=k;
        return;
    }
    ll mid=(l+r)>>1;
    pushdown(root,r-l+1);
    if(ql<=mid) change(root<<1,l,mid,ql,qr,k);
    if(qr>mid)  change(root<<1|1,mid+1,r,ql,qr,k);
    sum[root]=max(sum[root<<1],sum[root<<1|1]);
}
ll q(ll root,ll l,ll r,ll ql,ll qr)
{
    if(ql<=l&&qr>=r)
    {
        return sum[root];
    }
    ll mid=(l+r)>>1;
    pushdown(root,r-l+1);
    ll ans=0;
    if(ql<=mid)       ans=max(ans,q(root<<1,l,mid,ql,qr));
    if(qr>mid)        ans=max(ans,q(root<<1|1,mid+1,r,ql,qr));
    return ans;
}
int main()
{
    ll n,m,k;
    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld%lld",&stu[i].l,&stu[i].r,&stu[i].v);
    sort(stu+1,stu+1+n,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        stu[i].r--;			//這裏因爲在都端點當前牛下車的同時,其他牛也可以上車,所以右端點減一。
        ll res=q(1,1,m,stu[i].l,stu[i].r);	
        if(res<k)
        {
            ll cnt=min(k-res,stu[i].v);				
            change(1,1,m,stu[i].l,stu[i].r,cnt);
            ans+=cnt;
            //printf("l: %lld r: %lld cnt: %lld\n",stu[i].l,stu[i].r,cnt);
        }
    }
    printf("%lld\n",ans);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章