种树
题目描述
某条街被划为 (n) 条路段,这 (n) 条路段依次编号为 (1dots n)。每个路段最多可以种一棵树。现在居民们给出了 (h) 组建议,每组建议包含三个整数 (b,e,t),表示居民希望在路段 (b) 到 (e) 之间至少要种 (t) 棵树。这些建议所给路段的区间可以交叉。请问:如果要满足所有居民的建议,至少要种多少棵树。
输入格式
第一行为 (n),表示路段数。
第二行为 (h),表示建议数。
下面 (h) 行描述一条建议:(b, e, t),用一个空格分隔。
输出格式
输出只有一个数,为满足所有居民的建议,所需要种树的最少数量。
输入输出样例
样例输入
9
4
1 4 2
4 6 2
8 9 2
3 5 2
样例输出
5
数据范围与提示
(30\%) 的数据满足 (0<nle 1000),(0<hle 500);
(100\%) 的数据满足 (0<nle 3 imes 10^4),(hle 5000),(0<ble ele 3 imes 10^4),(tle e-b+1)。
尽可能将每棵树贡献到答案里尽量多,所以我们按照右端点排序,再尽可能往右边种。每次先扫描这个区间里面已经种上了几棵,从右往左补齐剩下的即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#define int long long
#define rep(i,a,n) for(register int i=a;i<=n;++i)
#define dwn(i,n,a) for(register int i=n;i>=a;--i)
using namespace std;
int h,n,book[100050];
struct node
{
int b,e,t;
}a[100050];
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x==0)return;
write(x/10);
putchar(x%10+'0');
}
bool cmp(node a,node b)
{
if(a.e==b.e)return a.b<b.b;
return a.e<b.e;
}
signed main()
{
n=read(),h=read();
rep(i,1,h)a[i].b=read(),a[i].e=read(),a[i].t=read();
sort(a+1,a+h+1,cmp);
rep(i,1,h)
{
int cnt=0;
rep(j,a[i].b,a[i].e)cnt+=book[j];
if(cnt>=a[i].t)continue;
dwn(j,a[i].e,a[i].b)
{
if(!book[j])
{
book[j]=1;
++cnt;
}
if(cnt==a[i].t)break;
}
}
int cnt=0;
rep(i,1,n)cnt+=book[i];
if(cnt)write(cnt);
else putchar('0');
return 0;
}
/*
9
4
1 4 2
4 6 2
8 9 2
3 5 2
*/