题目描述

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

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

输入输出格式

输入格式:

【输入】

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

第二行到\(K+1\)行:在第\(i+1\)行,将会告诉你第\(i\)组奶牛的信息:\(S_i\)\(E_i\)\(M_i\),彼

此用空格隔开。

输出格式:

【输出】

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

输入输出样例

输入样例#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\)

思路:
题意是给你几堆奶牛,每个奶牛都有想去的地方,给你一个汽车,汽车有一个容量和固定的行走路线,询问最多能搭载的奶牛的数量。

我们来考虑一种贪心的思想,按右端点从小到大排一遍序,为什么呢?后面说,然后对排好序的每堆奶牛依次进行遍历,如果当前有空位,空位大于这堆奶牛的数量,那就全上去,不然的话,就能上去几个就上去几个。这样下来的话,结果一定是最优的,其正确性不难证明,因为刚开始我们对每堆奶牛要到的地方从小到大排了序(即终点),那么每个位置最多只有一次奶牛上车,而且这些奶牛来自同一群,所以我们对每堆奶牛分别进行考虑即可,这就是为什么要按右端点排序的原因。贪心过程中,要维护最大值。因为要算最少的空位子,下面给出两种代码:

自己整理的题解

1、纯贪心&贪心:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 50007
using namespace std;
int ans,n,m,k,w[maxn];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int u,v,c;
}e[maxn];
const int inf=0x7fffffff;
inline bool cmp(node a, node b) {
  if(a.v!=b.v) return a.v<b.v;
  return a.u<b.u;
}
int main() {
  k=qread(),n=qread(),m=qread();
  for(int i=1;i<=k;++i) e[i].u=qread(),e[i].v=qread(),e[i].c=qread();
  sort(e+1,e+1+k,cmp);
  for(int i=1;i<=k;++i) {
    if(w[e[i].u]>=m) continue;
    int minn=inf;
    for(int j=e[i].u;j<=e[i].v;++j) {
      minn=min(m-w[j],minn);
      if(minn<=0) break;
    }
    if(minn>0) {
      if(minn>=e[i].c) { 
        for(int j=e[i].u;j<e[i].v;++j)
          w[j]+=e[i].c;
        ans+=e[i].c;
      }
      else {
        for(int j=e[i].u;j<e[i].v;++j)
          w[j]+=minn;
        ans+=minn;
      }
    }
  }
  printf("%d\n",ans);
  return 0;
}

2、线段树&贪心&排序:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 20007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int inf=0x7fffffff;
int n,k,m,maxx[maxn<<2],lazy[maxn<<2],zrj,w[50007];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int u,v,c;
}e[50007];
inline bool cmp(node a, node b) {
  if(a.v!=b.v) return a.v<b.v;
  return a.u<b.u;
}
inline void pushup(int rt) {
  maxx[rt]=max(maxx[ls],maxx[rs]);
}
inline void pushdown(int rt) {
  if(lazy[rt]) {
    maxx[ls]+=lazy[rt],lazy[ls]+=lazy[rt];
    maxx[rs]+=lazy[rt],lazy[rs]+=lazy[rt];
    lazy[rt]=0;
  }
}
void modify(int rt, int l, int r, int L, int R, int val) {
  if(L>r||R<l) return;
  if(L<=l&&r<=R) {
    lazy[rt]+=val,maxx[rt]+=val;
    return;
  }
  int mid=(l+r)>>1;
  pushdown(rt);
  modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
  pushup(rt);
}
int cmax(int rt, int l, int r, int L, int R) {
  if(L>r||R<l) return -inf;
  if(L<=l&&r<=R) return maxx[rt];
  int mid=(l+r)>>1,ans=-inf;
  pushdown(rt);
  if(L<=mid) ans=max(ans,cmax(ls,l,mid,L,R));
  if(R>mid) ans=max(ans,cmax(rs,mid+1,r,L,R));
  return ans;
}
int main() {
  k=qread(),n=qread(),m=qread();
  for(int i=1;i<=k;++i) e[i].u=qread(),e[i].v=qread(),e[i].c=qread();
  sort(e+1,e+1+k,cmp);
  for(int i=1;i<=k;++i) {
    int p=cmax(1,1,n,e[i].u,e[i].v-1);
    int minn=min(m-p,e[i].c);
    zrj+=minn,w[i]+=minn;
    modify(1,1,n,e[i].u,e[i].v-1,w[i]);
  }
  printf("%d\n",zrj);
  return 0;
}