[USACO20FEB] Timeline G

题目描述

Bessie 在过去的\(M\)天内参加了 \(N\) 次挤奶。但她已经忘了她每次挤奶是在哪个时候了。

对于第 \(i\) 次挤奶,Bessie 记得它不早于第 \(S_i\) 天进行。另外,她还有 \(C\) 条记忆,每条记忆形如一个三元组\((a,b,x)\)含义是第 \(b\) 次挤奶在第 \(a\) 次挤奶结束至少 \(x\) 天后进行。

现在请你帮 Bessie 算出在满足所有条件的前提下,每次挤奶的最早日期。

保证 Bessie 的记忆没有错误,这意味着一定存在一种合法的方案,使得:

\(i\) 次挤奶不早于第 \(S_i\) 天进行,且不晚于第 \(M\) 天进行;
所有的记忆都得到满足;

输入格式

第一行三个整数\(N,M,C\)。保证 \(1 \leq N,C \leq 10^5\),$ 2 \leq M \leq 10^9 $。

接下来一行包含 \(N\) 个整数\(S_1, S_2 , \ldots, S_n\),保证\(\forall 1 \leq i \leq n\),都满足\(1 \leq S_i \leq M\)

下面 \(C\) 行每行三个整数\(a,b,x\),描述一条记忆。保证\(a \neq b\),且\(1 \leq x \leq M\)

输出格式


输出 $N$ 行,每行一个整数,第 $i$ 行的数表示第 $i$ 次挤奶的最早日期。

题意分析

给定C组数量关系(也就是不等式),并且给定每次挤奶的最少时间(可以转换为不等式),求每次挤奶的可能的最早时间;很明显是差分约束系统的问题

1. 三元组(a,b,x) 用 \(T_i\) 表示第i次挤奶的时间 可以得到第一组不等式 \(T_b\)-\(T_a\) \(\geq\)\(x\)

2. 第i次挤奶不早于第\(S_i\)天 可以转换为第i次挤奶在第0次挤奶的\(S_i\)天后。
也就是 \(T_i-T_0\geq S_i\)
那么0就成为了天然的超级源点(原因:0联通了所有点,它可以联通整张图)

3. 在符合条件的情况下,要使每次挤奶的时间尽可能的提前,而前面的挤奶时间提前会使后面的时间可能提前,即前面的最优解是后面最优解的前置条件(也就是子问题),且求解方法相同,所以我们可以使用贪心的思想。

4. 差分约束系统的问题就是建完图后求最短/长路,而求最早时间,就是求\(T_i-T_0\)的最小值,就是建形如\(X_i-X_j\geq c\)的图,然后求第0次到第i次的最长路;而贪心的思想让我们很容易想到Dijkstra算法,而天数必定为正数,那图中的边权都为正数,不会有正负交替的情况,可以使用Dijkstra算法。

Code

#include<bits/stdc++.h>
using namespace std;
struct num{
	int to;
	int w;
	bool operator <(const num&a)const{
		return w<a.w;
	}//重载运算符
};
int n,m,c,a,b,x,s[100050],ans,dis[100050];
vector<num> mp[100050];
priority_queue<num> q;
void dijkstra(int s){
	dis[s]=0;
	q.push({s,0});
	while(!q.empty()){
		num u=q.top();
		q.pop();
		for(num i:mp[u.to]){
			if(dis[i.to]<dis[u.to]+i.w){
				dis[i.to]=dis[u.to]+i.w;
				q.push({i.to,dis[i.to]});
			}
		}
	}
}//最长路模板
int main(){
	cin>>n>>m>>c;
	for(int i=1;i<=n;i++){
		cin>>s[i];//i-0>=s[i]
		mp[0].push_back({i,s[i]});
	}//建立超级源点
	for(int i=1;i<=c;i++){
		cin>>a>>b>>x;//b-a>=x
		mp[a].push_back({b,x});
	}//建图
    dijkstra(0);
	for(int i=1;i<=n;i++){
		cout<<dis[i]<<endl;
	}
	return 0;
}
posted @ 2023-11-16 16:02  Qing_Nian  阅读(28)  评论(0)    收藏  举报