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% 的数据
我们将各个要求按右端点从小到大排序,如果右端点相同则按左端点从大到小排序,然后依次判断每个一段是否满足至少有 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)。
#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);
}