362. 区间
题目链接
362. 区间
给定 \(n\) 个区间 \([a_i,b_i]\) 和 \(n\) 个整数 \(c_i\)。
你需要构造一个整数集合 \(Z\),使得 \(\forall i \in [1,n]\),\(Z\) 中满足 \(a_i \le x \le b_i\) 的整数 \(x\) 不少于 \(c_i\) 个。
求这样的整数集合 \(Z\) 最少包含多少个数。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含三个整数 \(a_i,b_i,c_i\)。
输出格式
输出一个整数表示结果。
数据范围
\(1 \le n \le 50000\),
\(0 \le a_i,b_i \le 50000\),
\(1 \le c_i \le b_i-a_i+1\)
输入样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
输出样例:
6
解题思路
差分约束
设 \(x[i]\) 表示 \(i\) 这个数是否选了,则有 \(0\leq x[i]\leq 1\),\(s[i]\) 为其前缀和,要求 \(a\sim b\) 中的数不少于 \(c\) 个,即 \(s[b]-s[a]\geq c\),另外前缀和有 \(s[i]\leq s[i+1]\),由于是前缀和,而 \(a,b\) 可能为 \(0\),则所有的 \(a,b\) 都需要右移一位,根据这些不等式差分约束,求最小值即求解最长路,最后 \(s[50001]\) 即为答案
- 时间复杂度:\(O(kn)\)
代码
// Problem: 区间
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/364/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=50005;
int n,d[N];
bool v[N];
vector<PII> adj[N];
void spfa()
{
memset(d,-0x3f,sizeof d);
queue<int> q;
q.push(0);
d[0]=0,v[0]=true;
while(q.size())
{
int x=q.front();
q.pop();
v[x]=false;
for(auto t:adj[x])
{
int y=t.fi,w=t.se;
if(d[y]<d[x]+w)
{
d[y]=d[x]+w;
if(!v[y])v[y]=true,q.push(y);
}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
a++,b++;
adj[a-1].pb({b,c});
}
for(int i=1;i<=50001;i++)
adj[i].pb({i-1,-1}),adj[i-1].pb({i,0});
spfa();
cout<<d[50001];
return 0;
}