POJ1201 Intervals <差分约束系统>

Problem

Intervals

Description

You are given nn closed, integer intervals [ai,bi][a_i, b_i] and nn integers c1cnc_1\sim c_n.
Write a program that:
reads the number of intervals, their end points and integers c1cnc_1\sim c_n from the standard input, computes the minimal size of a set ZZ of integers which has at least cic_i common elements with interval [ai,bi][a_i, b_i], for each i=1,2,,ni=1,2,\cdots ,n, writes the answer to the standard output.

Input

The first line of the input contains an integer nn (1n5×1041\le n\le 5\times 10^4) – the number of intervals. The following n lines describe the intervals. The (i+1)th(i+1)^{th} line of the input contains three integers aia_i, bib_i and cic_i separated by single spaces and such that 0aibi5×1040\le a_i\le b_i\le 5\times 10^4 and 1cibiai+11\le c_i\le b_i - a_i+1.

Output

The output contains exactly one integer equal to the minimal size of set ZZ sharing at least cic_i elements with interval [ai,bi][a_i, b_i], for each i=1,2,,ni=1,2,\cdots ,n.

Sample Input

1
2
3
4
5
6
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

1
6

标签:差分约束系统

Translation

给出nn个区间,试确定一个集合使得对于i=1ni=1\sim n,第ii个区间内至少有cic_i个数,并使得此集合尽量小,输出最小大小。

Solution

首先用前缀和。sum[i]sum[i]表示从11ii中共选出多少个数到集合中。这样对于集合[ai,bi][a_i,b_i],有sum[bi]sum[ai1]cisum[b_i]-sum[a_i-1]\ge c_i,于是我们可以从点ai1a_i-1bib_i连一条权值为cic_i的边。因为题意是要满足所有的边,所以我们需要找最长路。
此题有一些细节问题。首先,找最长路需要起点和终点,我们需要找到这些集合覆盖的范围,即找到左端点(其实应该是左端点1-1)的最小值ss和右端点的最大值tt,找sstt的最大值。此外,光有上述的那些边时无法构成一个连通图的,所以我们需要找一些隐含条件。可以发现有sum[i]sum[i1]0sum[i]-sum[i-1]\ge 0sum[i]sum[i1]1sum[i]-sum[i-1]\le 1,为了保持一致,应将后面的式子转化为大于等于,即sum[i1]sum[i]1sum[i-1]-sum[i]\ge -1,这样对于i=s+1ti=s+1\sim t,从i1i-1ii连接一条权值为00的路,从iii1i-1连接一条权值为1-1的路,之后就可以直接用SPFASPFA找最长路了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAX_N 50000
using namespace std;
int n, cnt, s, t, pre[MAX_N+5], dis[MAX_N+5];
struct node {int v, c, nxt;} E[MAX_N*3+5];
void insert(int u, int v, int c) {
E[++cnt].v = v, E[cnt].c = c;
E[cnt].nxt = pre[u], pre[u] = cnt;
}
void SPFA() {
queue <int> que;
bool inque[MAX_N+5];
memset(dis, 128, sizeof(dis));
memset(inque, 0, sizeof(inque));
dis[s] = 0;
que.push(s), inque[s] = true;
while (!que.empty()) {
int u = que.front();
for (int i = pre[u]; i; i = E[i].nxt) {
int v = E[i].v, c = E[i].c;
if (dis[u]+c > dis[v]) {
dis[v] = dis[u]+c;
if (!inque[v]) que.push(v), inque[v] = true;
}
}
que.pop(), inque[u] = false;
}
}
int main() {
while (scanf("%d", &n) != EOF) {
cnt = 0, s = 50000, t = 0;
memset(pre, 0, sizeof(pre));
memset(E, 0, sizeof(E));
for (int i = 0; i < n; i++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
insert(u, v+1, c);
s = min(s, u);
t = max(t, v+1);
}
for (int i = s; i < t; i++) insert(i, i+1, 0), insert(i+1, i, -1);
SPFA();
printf("%d\n", dis[t]);
}
return 0;
}