description
有$n$个区间 $[a_i, b_i]$, 以及$c_i$, 有一个整数集合Z, 要求对于每个区间$[a_i, b_i] 中的数不少于$c_i$个。
Solution
设$s_k$ 表示前k个数至少要选几个, 显然有$s[b_i] - s[a_i - 1] >= c_i$, 然后就是一个很显然的差分约束
另外还需满足: $s_{k+1} - s_k >= 0$, $s_{k+1} - s_k <= 1$
所以从$a_i - 1$ 向 $b_i$连一条长度为$c_i$的边
从$k$向$k+1$连长度为$0$ 的边
从$k+1$向$k$连长度为$-1$的边
跑一遍最长路即可求出答案
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #define rd read() 6 #define rep(i,a,b) for(int i = (a); i <= (b); ++i) 7 #define per(i,a,b) for(int i = (a); i >= (b); --i) 8 using namespace std; 9 10 const int N = 5e5 + 1e4; 11 const int M = 3e6; 12 const int inf = ~0U >> 2; 13 14 int n, dis[N], vis[N], cnt[N]; 15 int tot, head[N]; 16 17 queue<int> q; 18 19 struct edge { 20 int nxt, to, val; 21 }e[M]; 22 23 int read() { 24 int X = 0, p = 1; char c = getchar(); 25 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 26 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 27 return X * p; 28 } 29 30 void add(int u, int v, int val) { 31 e[++tot].to = v; 32 e[tot].val = val; 33 e[tot].nxt = head[u]; 34 head[u] = tot; 35 } 36 37 int spfa() { 38 q.push(0); 39 dis[0] = 0; 40 for(int u; !q.empty();) { 41 u = q.front(); q.pop(); 42 vis[u] = 0; 43 for(int i = head[u]; i; i = e[i].nxt) { 44 int nt = e[i].to; 45 if(dis[nt] >= dis[u] + e[i].val) continue; 46 dis[nt] = dis[u] + e[i].val; 47 if(!vis[nt]) vis[nt] = 1, q.push(nt); 48 } 49 } 50 return dis[(int)5e5 + 1]; 51 } 52 53 int main() 54 { 55 n = rd; 56 for(int i = 0; i <= 5e5; ++i) { 57 add(i, i + 1, 0); add(i + 1, i, -1); 58 } 59 memset(dis, -1, sizeof(dis)); 60 rep(i, 1, n) { 61 int a = rd, b = rd, c = rd; 62 add(a, b + 1, c); 63 } 64 printf("%d\n", spfa()); 65 }