Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2743 | Accepted: 955 |
Description
Input
Output
Sample Input
3 0 4 0 2 3 3 4 2 0 0 1
Sample Output
5
Hint
给出n个小区间[l,r],更新这段区间的代价为c,求覆盖一段区间[m,e]的最小值。
线段树+DP
首先应该将小区间排个序,对于每个区间[l,r],它可以在[l-1,r]区间上覆盖,找到这段区
间的最小代价,最小代价加上这段区间的代价与r点的代价比较,更新包含r点的区间
段就可以了。区间查询用线段树。
代码:
//94ms #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=100000+100; const int inf=199999999; struct node { int minc; } tree[maxn<<2]; struct Cow { int l; int r; int c; } cow[maxn]; bool cmp(Cow a,Cow b) { if(a.l==b.l) return a.r<b.r; return a.l<b.l; } void build(int rt,int l,int r)//建树 { tree[rt].minc=inf; if(l==r) return; int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); } void update(int rt,int k,int v,int l,int r)//更新所有包含k的区间 { if(l==r) { tree[rt].minc=min(tree[rt].minc,v); return; } int m=(l+r)>>1; if(k<=m) update(rt<<1,k,v,l,m); else update(rt<<1|1,k,v,m+1,r); tree[rt].minc=min(tree[rt<<1].minc,tree[rt<<1|1].minc); } int query(int rt,int l,int r,int L,int R)//查找L,R区间内的最小值 { if(l>=L&&r<=R) return tree[rt].minc; int mid=(l+r)>>1; int temp = inf; if(L<=mid) temp=query(rt<<1,l,mid,L,R); if(R>mid) temp=min(temp,query(rt<<1|1,mid+1,r,L,R)); return temp; } int main() { int n,m,e; while(~scanf("%d%d%d",&n,&m,&e)) { for(int i=0; i<n; i++) scanf("%d%d%d",&cow[i].l,&cow[i].r,&cow[i].c); int sign=1; sort(cow,cow+n,cmp); build(1,m-1,e); int cur=m-1; update(1,cur,0,m-1,e);//将m-1点赋为0. for(int i=0; i<n; i++) { if(cow[i].l>cur+1)//不能全部覆盖 { sign=0; break; } int temp=query(1,m-1,e,cow[i].l-1,cow[i].r); update(1,cow[i].r,temp+cow[i].c,m-1,e); cur=max(cur,cow[i].r); } if(sign) printf("%d\n",query(1,m-1,e,e,e)); else printf("-1\n"); } return 0; }
poj 3171 Cleaning Shifts(区间的最小覆盖价值)
原文地址:http://blog.csdn.net/caduca/article/details/40538073