bzoj4489 [Jsoi2015]地铁线路 最短路

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4489

题解

感觉又被骗了。看这道题的 AC 人数不多,以为是一道很好的题目。结果发现是一个非常一般的最短路啊。

第一问的话,相当于同一个集合内的点可以瞬移,不需要花钱。于是可以每条线路建一个点,把每个站点向所在线路连边,边权为 \(0\);每条道路向站点连边,边权为 \(1\)。显然从 \(S\)\(T\) 的最短路就是第一问的答案。最短路可以通过 01bfs 实现。

然后第二问的话,也可以继续建图来做。但是有一个更方便的做法。我们可以通过第一问得到的最短路给每一条线路和每个站点分层。然后对于同一层,枚举每一条线路,用这条线路上低一层的点来更新本层的点。(更新可以通过前后缀最大值来实现)


代码如下。

#include<bits/stdc++.h>
#include<tr1/unordered_map>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int N = 3e5 + 50000 + 7;
const int M = 3e5 + 7;
const int INF = 0x3f3f3f3f;

int n, m, nod, S, T, hd, tl;
int dis[N], p[N], mxt[N], mxt2[N], pre[N], suf[N];
std::deque<int> q;
std::tr1::unordered_map<std::string, int> mp;
std::vector<int> v[N];
char tmp[50];

struct Edge { int to, ne; } g[N * 6]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }

inline void build() {
	for (int i = 1; i <= n; ++i) {
		int len = v[i].size();
		for (int j = 0; j < len; ++j) adde(i + m, v[i][j]);
	}
}

inline void bfs() {
	q.push_back(S);
	memset(dis, -1, sizeof(dis)), dis[S] = 0;
	while (!q.empty()) {
		int x = q.front(); q.pop_front();
		if (x <= m) {
			for fec(i, x, y) if (!~dis[y]) dis[y] = dis[x] + 1, q.push_back(y);
		} else for fec(i, x, y) if (!~dis[y]) dis[y] = dis[x], q.push_front(y);
	}
}

inline bool cmp(const int &x, const int &y) { return dis[x + m] < dis[y + m]; }
inline void work() {
	build();
	bfs();
	for (int i = 1; i <= n; ++i) p[i] = i;
	std::sort(p + 1, p + n + 1, cmp);
	int r = 0;
	while (r < n && dis[p[r + 1] + m] <= 0) ++r;
	for (int i = 1; i <= n; ++i) {
		int l = r + 1;
		while (r < n && dis[p[r + 1] + m] == i) ++r;
		for (int j = l; j <= r; ++j) {
			int id = p[j], len = v[id].size();
			pre[0] = suf[len + 1] = -INF;
			for (int k = 0; k < len; ++k) pre[k + 1] = std::max(pre[k] + 1, dis[v[id][k]] == i - 1 ? mxt[v[id][k]] : -INF);
			for (int k = len - 1; ~k; --k) suf[k + 1] = std::max(suf[k + 2] + 1, dis[v[id][k]] == i - 1 ? mxt[v[id][k]] : -INF);
			for (int k = 0; k < len; ++k) if (dis[v[id][k]] == i) smax(mxt[v[id][k]], std::max(pre[k + 1], suf[k + 1]));
		}
	}
	printf("%d\n", dis[T]);
	printf("%d\n", mxt[T]);
}

inline void init() {
	read(n), read(m);
	for (int i = 1; i <= m; ++i) scanf("%s", tmp), mp[tmp] = i;
	for (int i = 1; i <= n; ++i) {
		int l;
		read(l);
		while (l--) scanf("%s", tmp), v[i].pb(mp[tmp]);
	}
	scanf("%s", tmp), S = mp[tmp];
	scanf("%s", tmp), T = mp[tmp];
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}
posted @ 2019-09-18 21:23  hankeke303  阅读(256)  评论(0编辑  收藏  举报