CodeForces 827F. Dirty Arkady's Kitchen

Arkady likes to walk around his kitchen. His labyrinthine kitchen consists of several important places connected with passages. Unfortunately it happens that these passages are flooded with milk so that it's impossible to pass through them. Namely, it's possible to pass through each passage in any direction only during some time interval.

The lengths of all passages are equal and Arkady makes through them in one second. For security reasons, Arkady can never stop, also, he can't change direction while going through a passage. In other words, if he starts walking in some passage, he should reach its end and immediately leave the end.

Today Arkady needs to quickly reach important place n from place 1. He plans to exit the place 1 at time moment 0 and reach the place nas early as he can. Please find the minimum time he should spend on his way.

Input

The first line contains two integers n and m (1 ≤ n ≤ 5·1050 ≤ m ≤ 5·105) — the number of important places and the number of passages, respectively.

After that, m lines follow, each of them describe one passage. Each line contains four integers abl and r (1 ≤ a, b ≤ na ≠ b0 ≤ l < r ≤ 109) — the places the passage connects and the time segment during which it's possible to use this passage.

Output

Print one integer — minimum time Arkady should spend to reach the destination. If he can't reach the place n, print -1.

Examples
input
5 6
1 2 0 1
2 5 2 3
2 5 0 1
1 3 0 1
3 4 1 2
4 5 2 3
output
3
input
2 1
1 2 1 100
output
-1
Note

In the first example Arkady should go through important places 1 → 3 → 4 → 5.

In the second example Arkady can't start his walk because at time moment 0 it's impossible to use the only passage.

题意:给一个图,每条边有一个出现时间[l, r],边权都为1,必须一直走,求1到n最短路

题解:

DP

想到DP边就好做多了,按时间奇偶和方向拆边

首先用一个堆维护边的DP值,然后它可以更新反向边,然后同向的边按照l排序之后有单调性,直接更新就好了

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair < int, int > pii;

inline int Read()
{
	int x = 0, f = 1, c = getchar();
	for (; !isdigit(c); c = getchar())
		if (c == '-')
			f = -1;
	for (;  isdigit(c); c = getchar())
		x = x * 10 + c - '0';
	return x * f;
}

const int MAXN = 500005;
const int INF = 0x3f3f3f3f;

struct Node { int v, x, t, i; bool operator < (const Node &b) const { return v > b.v; } };
struct Edge { int p, l, r, v; };
int n, m, cur[MAXN][2];
vector < Edge > G[MAXN];
vector < pii > adj[MAXN][2];
vector < int > f[MAXN][2];
priority_queue < Node > Q;

int main()
{
#ifdef wxh010910
	freopen("data.in", "r", stdin);
#endif
	n = Read(), m = Read();
	if (n == 1)
		return puts("0"), 0;
	for (int i = 1, u, v, l, r; i <= m; i ++)
		u = Read(), v = Read(), l = Read(), r = Read(), G[u].pb({v, l, r, G[v].size()}), G[v].pb({u, l, r, G[u].size() - 1});
	for (int i = 1; i <= n; i ++)
		for (int j = 0; j < 2; j ++)
		{
			f[i][j].resize(G[i].size(), INF);
			for (int k = 0; k < G[i].size(); k ++)
				adj[i][j].pb(mp(G[i][k].l + ((G[i][k].l & 1) ^ j), k));
			sort(adj[i][j].begin(), adj[i][j].end());
		}
	for (int i = 0; i < G[1].size(); i ++)
		if (!G[1][i].l)
			f[1][0][i] = 0, Q.push({0, 1, 0, i});
	while (!Q.empty())
	{
		Node tmp = Q.top(); Q.pop();
		int x = tmp.x, t = tmp.t, p = tmp.i, r = G[x][p].v, y = G[x][p].p, v = f[x][t][p], d = G[x][p].r - ((G[x][p].r & 1) ^ t);
		if (tmp.v > v)
			continue;
		//printf("%d %d %d %d\n", x, t, p, v);
		if (f[y][t ^ 1][r] > v + 1 && G[x][p].l <= v + 1 && G[x][p].r >= v + 1)
			f[y][t ^ 1][r] = v + 1, Q.push({v + 1, y, t ^ 1, r});
		if (v > d)
			continue;
		while (cur[x][t] < G[x].size())
		{
			pii g = adj[x][t][cur[x][t]];
			if (g.xx > d)
				break;
			if (max(g.xx, v) < f[x][t][g.yy])
				f[x][t][g.yy] = max(g.xx, v), Q.push({max(g.xx, v), x, t, g.yy});
			cur[x][t] ++;
		}
	}
	int ans = INF;
	for (int i = 0; i < G[n].size(); i ++)
		for (int j = 0; j < 2; j ++)
			ans = min(ans, f[n][j][i]);
	if (ans == INF)
		ans = -1;
	return printf("%d\n", ans), 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值