P1250 种树

P1250 种树

题目背景

一条街的一边有几座房子,因为环保原因居民想要在路边种些树。

题目描述

路边的地区被分割成块,并被编号成 1 , 2 , … , n 1, 2, \ldots,n 1,2,,n。每个部分为一个单位尺寸大小并最多可种一棵树。

每个居民都想在门前种些树,并指定了三个号码 b b b e e e t t t。这三个数表示该居民想在地区 b b b e e e 之间(包括 b b b e e e)种至少 t t t 棵树。

居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量。

输入格式

输入的第一行是一个整数,代表区域的个数 n n n

输入的第二行是一个整数,代表房子个数 h h h

3 3 3 到第 ( h + 2 ) (h + 2) (h+2) 行,每行三个整数,第 ( i + 2 ) (i + 2) (i+2) 行的整数依次为 b i , e i , t i b_i, e_i, t_i bi,ei,ti,代表第 i i i 个居民想在 b i b_i bi e i e_i ei 之间种至少 t i t_i ti 棵树。

输出格式

输出一行一个整数,代表最少的树木个数。

样例输入
9
4
1 4 2
4 6 2
8 9 2
3 5 2
样例输出
5

数据规模

对于 100 % 100\% 100% 的数据

  • 1 ≤ n ≤ 3 × 1 0 4 1 \leq n \leq 3 \times 10^4 1n3×104 1 ≤ h ≤ 5 × 1 0 3 1 \leq h \leq 5 \times 10^3 1h5×103
  • 1 ≤ b i ≤ e i ≤ n 1 \leq b_i \leq e_i \leq n 1biein 1 ≤ t i ≤ e i − b i + 1 1 \leq t_i \leq e_i - b_i + 1 1tieibi+1

题解

我们将各个要求按右端点从小到大排序,如果右端点相同则按左端点从大到小排序,然后依次判断每个一段是否满足至少有 t t t棵树。如果不满足,则从右开始种树,直到满足为止。因为右端点从小到大,所以种在右边一定比左边更优。所以这样做的结果一定最优。

每一段处理时间复杂度为 O ( n ) O(n) O(n),所以总时间复杂度为 O ( n h ) O(nh) O(nh),但跑不满,所以还是可以过的。用链表维护没有种树的区域,用树状数组来单点修改和区间查询,时间复杂度可将为 O ( n + h l o g   n ) O(n+hlog \ n) O(n+hlog n)

code

#include
using namespace std;
int n,h,ans,z[30005];
struct node{
	int x,y,t;
}w[5005];
bool cmp(node ax,node bx){
	if(ax.y!=bx.y) return ax.y<bx.y;
	return ax.x>bx.x;
}
int main()
{
	scanf("%d%d",&n,&h);
	for(int i=1;i<=h;i++)
	scanf("%d%d%d",&w[i].x,&w[i].y,&w[i].t);
	sort(w+1,w+h+1,cmp);
	for(int i=1;i<=h;i++){
		for(int j=w[i].x;j<=w[i].y&&w[i].t;j++) w[i].t-=z[j];
		if(w[i].t>0){
			for(int j=w[i].y;j>=w[i].x&&w[i].t;j--){
				if(!z[j]){
					z[j]=1;--w[i].t;
				}
			}
		}
	}
	for(int i=1;i<=n;i++) ans+=z[i];
	printf("%d",ans);
}

你可能感兴趣的:(题解,1024程序员节,c++)