poj2376 Cleaning Shifts【线段树】【DP】

Cleaning Shifts

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 32561   Accepted: 7972

Description

Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cleaning chores around the barn. He always wants to have one cow working on cleaning things up and has divided the day into T shifts (1 <= T <= 1,000,000), the first being shift 1 and the last being shift T.

Each cow is only available at some interval of times during the day for work on cleaning. Any cow that is selected for cleaning duty will work for the entirety of her interval.

Your job is to help Farmer John assign some cows to shifts so that (i) every shift has at least one cow assigned to it, and (ii) as few cows as possible are involved in cleaning. If it is not possible to assign a cow to each shift, print -1.

Input

* Line 1: Two space-separated integers: N and T

* Lines 2..N+1: Each line contains the start and end times of the interval during which a cow can work. A cow starts work at the start time and finishes after the end time.

Output

* Line 1: The minimum number of cows Farmer John needs to hire or -1 if it is not possible to assign a cow to each shift.

Sample Input

3 10
1 7
3 6
6 10

Sample Output

2

Hint

This problem has huge input data,use scanf() instead of cin to read data to avoid time limit exceed.

INPUT DETAILS:

There are 3 cows and 10 shifts. Cow #1 can work shifts 1..7, cow #2 can work shifts 3..6, and cow #3 can work shifts 6..10.

OUTPUT DETAILS:

By selecting cows #1 and #3, all shifts are covered. There is no way to cover all the shifts using fewer than 2 cows.

Source

USACO 2004 December Silver

https://www.cnblogs.com/wyboooo/p/9808378.html

和poj3171基本一样,改一下输入和范围即可。

  1 #include <iostream>
  2 #include <set>
  3 #include <cmath>
  4 #include <stdio.h>
  5 #include <cstring>
  6 #include <algorithm>
  7 using namespace std;
  8 typedef long long LL;
  9 #define inf 0x7f7f7f7f
 10
 11 const int maxn = 25000 + 5;
 12 const int maxtime = 1e6 + 5;
 13 struct node{
 14     int st, ed, cost;
 15 }cow[maxn];
 16 bool cmp(node a, node b)
 17 {
 18     return a.ed < b.ed;
 19 }
 20 LL tree[maxtime << 2];//区间中f[]最小值
 21 int n, L, R;
 22
 23 void pushup(int rt)
 24 {
 25     tree[rt] = min(tree[rt << 1], tree[rt << 1|1]);
 26 }
 27
 28 void build(int rt, int l, int r)
 29 {
 30     if(l == r){
 31         tree[maxn] = inf;
 32         return;
 33     }
 34     int mid = (l + r) / 2;
 35     build(rt<<1, l, mid);
 36     build(rt<<1|1, mid + 1, r);
 37     pushup(rt);
 38 }
 39
 40 void update(int x, LL val, int l, int r, int rt)
 41 {
 42     if(l == r){
 43         tree[rt] = min(tree[rt], val);
 44         return;
 45     }
 46     int m = (l + r) / 2;
 47     if(x <= m){
 48         update(x, val, l, m, rt<<1);
 49     }
 50     else{
 51         update(x, val, m + 1, r, rt<<1|1);
 52     }
 53     pushup(rt);
 54 }
 55
 56 LL query(int L, int R, int l, int r, int rt)
 57 {
 58     if(L <= l && R >= r){
 59         return tree[rt];
 60     }
 61     int m = (l + r) / 2;
 62     LL ans = inf;
 63     if(L <= m){
 64         ans = min(ans, query(L, R, l, m, rt<< 1));
 65     }
 66     if(R > m){
 67         ans = min(ans, query(L, R, m + 1, r, rt<<1|1));
 68     }
 69     pushup(rt);
 70     return ans;
 71 }
 72
 73 int main()
 74 {
 75     while(scanf("%d%d", &n, &R) != EOF){
 76         R+=1;
 77         memset(tree, 0x7f, sizeof(tree));
 78         for(int i = 1; i <= n; i++){
 79             scanf("%d%d", &cow[i].st, &cow[i].ed);
 80             cow[i].st+=1;cow[i].ed+=1;
 81             cow[i].cost = 1;
 82         }
 83         sort(cow + 1, cow + 1 + n, cmp);
 84
 85         build(1, 1, R);
 86
 87         update(1, 0, 1, R, 1);
 88         //cout<<"yes"<<endl;
 89         //int far = L;
 90         bool flag = true;
 91         for(int i = 1; i <= n; i++){
 92             /*if(cow[i].st > far + 1){
 93                 flag = false;
 94             //    break;
 95             }*/
 96             int a = max(1, cow[i].st - 1);
 97             int b = min(R, cow[i].ed);
 98             //cout<<a<<" "<<b<<endl;
 99             LL f = query(a, b, 1, R, 1);
100             f += cow[i].cost;
101             //cout<<f<<endl;
102             update(b, f, 1, R, 1);
103             //far = max(far, cow[i].ed);
104             //cout<<far<<endl;
105         }
106         //cout<<"yes"<<endl;
107
108         LL ans = query(R, R, 1, R, 1);
109         if(ans >= inf){
110             printf("-1\n");
111         }
112         else{
113                 printf("%lld\n", ans);
114
115         //else{
116         //    printf("-1\n");
117         }
118
119     }
120
121 }

原文地址:https://www.cnblogs.com/wyboooo/p/9808395.html

时间: 2024-10-14 03:35:02

poj2376 Cleaning Shifts【线段树】【DP】的相关文章

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

ZOJ3632 线段树+DP

买西瓜吃,每个西瓜有两个参数,一个是p代表价格,一个是t代表能吃几天,要求n天每天都能吃西瓜,而且如果你今天买了,以前买的还没吃完 那么都得扔了,求最小花费,还真想不到用线段树+DP,最后看了一下别人的标题,想了一下,DP方程挺好推的,线段树也只是单点查询, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #inclu

HDU6447 YJJ&#39;s Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP

YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 253    Accepted Submission(s): 62 Problem Description YJJ is a salesman who has traveled through western country. YJJ is always on

[HDU 6447][YJJ&#39;s Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6447 题意: 左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值. 一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值. 问从(0,0)到(10^9,10^9)的路径最大权值是多少. 思路: 网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[

CF932F(李超线段树+dp)

CF932F(李超线段树+dp) 此题又是新玩法, 李超线段树合并优化\(dp\) 一个显然的\(\Theta(n^2)dp\): \(dp[x]\)表示从x出发到叶子节点的最小代价 \(dp[x] = \min(dp[y] + a[x] * b[y]) ~~(y \in subtree(x))\) 如果我们将\(b[y]\)看成斜率, \(dp[y]\)看成纵截距, \(a[x]\)看成横坐标, 那么问题转为了在平面上有一些直线, 选出与直线\(x = a[x]\)相交的最靠下的点吗, 李超线

UVa 12299 RMQ with Shifts(线段树)

线段树,没了.. ----------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cctype> #define rep(i,n) for(int i=0;i<n

【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

[BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位置,使得总费用最小. 输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述. 第

hdu4521(线段树+dp)

传送门:小明系列问题——小明序列 题意:有n个数,求间距大于d的最长上升序列. 分析:dp[i]表示在i点以a[i]结束距离大于d的最长上升序列,然后每更新到第i点时,取i-d之前小于a[i]的数为结束的最长上升序列进行状态转移,并维护前i-d之前的最大上升序列,维护i-d之前的每点为结束的最长上升序列用线段树维护即可. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #inc

lightoj1085 线段树+dp

1 //Accepted 7552 KB 844 ms 2 //dp[i]=sum(dp[j])+1 j<i && a[j]<a[i] 3 //可以用线段树求所用小于a[i]的dp[j]的和 4 //需要离散化 5 #include <cstdio> 6 #include <cstring> 7 #include <iostream> 8 #include <queue> 9 #include <cmath> 10 #