[USACO23FEB] Moo Route II S 题解

比较有意思。

无法保证每个点只被访问一遍,而此题每条边显然不会重复走,考虑保证每条边仅走一次。

一种 naive 的想法就是标记边是否走过。举个例子:

for(int i=1; i<=n; i++)
	if(vis[i]) continue;

仍然是 O ( n ) 。 O(n)。 O(n)

然后就考虑每次只访问有必要的边。对 u u u 出边按 r r r 排序,二分找出当前时间下还有必要访问的边。排序后访问到一条走过的边,显然就不用继续遍历接下来的出边了。

#include
#define int long long
using namespace std;

const int N = 2e5 + 5;

struct Edge{
	int c, r, d, s;
	bool vis;
};

int n, m, a[N], dis[N];

vector <Edge> G[N];

void dfs(int u, int T)
{
	int l = 0, r = G[u].size() - 1, mid, pos = 1e9;
	while(l <= r)
	{
		mid = l + r >> 1;
		if(G[u][mid].r >= T) pos = mid, r = mid - 1;
		else l = mid + 1;
	}
	for(int i = pos; i < G[u].size(); i ++ )
	{
		if(G[u][i].vis) return;
		G[u][i].vis = 1;
		int to = G[u][i].d;
		if(G[u][i].s < dis[to]) 
			dis[to] = G[u][i].s, dfs(to, G[u][i].s + a[to]);
	}
}

signed main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	
	cin >> n >> m;
	
	for(int i=1; i<=m; i++)
	{
		Edge x; x.vis = 0;
		cin >> x.c >> x.r >> x.d >> x.s;
		G[x.c].push_back(x);
	}
	
	for(int i=1; i<=n; i++)
		cin >> a[i], dis[i] = 1e9;
	
	for(int i=1; i<=n; i++) 
		sort(G[i].begin(), G[i].end(), [](Edge &x, Edge &y){return x.r < y.r;});
	
	dis[1] = 0;
	
	dfs(1, 0);
	
	for(int i=1; i<=n; i++)
	{
		if(dis[i] == 1e9) cout << "-1\n";
		else cout << dis[i] << "\n";
	} 
}
 

你可能感兴趣的:(题解,c++)