题解:P14307 【MX-J27-T4】点灯

思路

除非特别声明,以下讨论中默认 \(u\) 不为源点(\(1\) 号点)且有解,默认边 \((u,v,w)\)\(u,v\) 交换后等价。\(\oplus\) 为异或。

显然,一个点灯人如果能在第 \(t_u\) 夜到达 \(u\) 点,那么第 \(t_u+2k(k\in \N)\)\(u\) 点就一定有点灯人。考虑到达 \(u\) 后再沿着到达 \(u\) 的最后一条边来回即可。所以我们可以试着分别去求对于偶数和奇数夜,最早哪夜有点灯人。如果我们已经求出来了 \(d_{u,0}\) 表示最早的偶数夜有点灯人,\(d_{v,1}\) 表示最早的奇数夜有点灯人,那么答案就是 \(\min(\max\{d_{u,0}\},\max\{d_{u,1}\})\)

接下来考虑怎么去求。我们想知道每个点的奇偶两种情况最早什么时候到达,也就是最短路了。对于 \(w_i\) 的限制,这里的处理可以参见这道题的解法:如果目前考虑到 \(d_{u,p}\),那么对于边 \((u,v,w)\),就有两种情况:\(w\equiv p\pmod{2}\),则用 \(\max(w+1,d_{u,p}+1)\)\(d_{v,p\oplus 1}\) 松弛;否则用 \(\max(w,d_{u,p}+1)\)\(d_{v,p}\) 松弛。因为你可以跑来回跑 \(2k(k\in\N)\) 天。你可能觉得可以通过奇环跑奇数天,但这种情况会被 \(d_{u,p\oplus 1}\) 考虑到。所以是正确的。初始状态显然是 \(d_{1,0}=0\)

那么什么情况下无解呢?你可能以为只有计算后得到的答案是 \(+\infin\) 才无解,但这样你会发现你无法通过全部样例。因为我们转移的时候默认了有一条到达 \(u\) 的路。对于除了源点以外的点,你到达了那儿确实是一定如此的;但是源点最开始并不一定有到达源点的路,这种情况需要特判,即和源点相连的每条边 \((1,v,w)\)\(w\) 都大于 \(1\) 的情况。

代码

/*********************************************************************
    程序名:
    版权:
    作者:
    日期: 2025-10-25 17:09
    说明:
*********************************************************************/
#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fst first
#define sec second

#define p_q priority_queue
#define u_map unordered_map

#define rep(i,x,y) for(int i=x;i<=y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using i128 = __int128;

const int N = 3e4+50;
const ll inf = 1e18;

vector<pair<int, ll> > g[N];
ll d[N][2];
int vis[N][2];

void mian() {
	int n, m, o;
	cin >> n >> m >> o;
	bool isok = 0;
	rep(i, 1, m) {
		int u, v;
		ll w;
		cin >> u >> v >> w;
		g[u].pb(mp(v, w)), g[v].pb(mp(u, w));
		if (min(u, v) == 1 && w == 1)
			isok = 1;
	}
	rep(i, 1, n) d[i][0] = d[i][1] = inf, vis[i][0] = vis[i][1] = 0;
	p_q<pair<ll, pair<int, int> > > q; //全都取加法逆元就不用写一长串了
	d[1][0] = 0, q.push({0, {1, 0}});
	while (q.size()) {
		int u = q.top().sec.fst, p = q.top().sec.sec;
		q.pop();
		if (vis[u][p])
			continue;
		vis[u][p] = 1;
		for (auto qwq : g[u]) {
			int v = qwq.fst;
			ll w = qwq.sec;
			if (w % 2 != p) {
				if (!vis[v][w % 2] && max(w, d[u][p] + 1) < d[v][w % 2])
					d[v][w % 2] = max(w, d[u][p] + 1), q.push({-max(w, d[u][p] + 1), {v, w % 2}});
			} else {
				if (!vis[v][(w + 1) % 2] && max(w + 1, d[u][p] + 1) < d[v][(w + 1) % 2])
					d[v][(w + 1) % 2] = max(w + 1, d[u][p] + 1), q.push({-max(w + 1, d[u][p] + 1), {v, (w + 1) % 2}});
			}
		}
	}
	ll ans1 = 0, ans2 = 0;
	rep(i, 1, n) {
		ans1 = max(ans1, d[i][0]);
	}
	rep(i, 1, n) {
		ans2 = max(ans2, d[i][1]);
	}
	ll ans = min(ans1, ans2);
	cout << (ans >= inf || !isok ? -1 : o *ans) << '\n';
	rep(i, 1, n) {
		g[i].clear();
	} //多测清空
}

int main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int __, _;
	cin >> __ >> _;
	while (_-->0) {
		mian();
	}

	return 1004120712;
}

posted @ 2025-10-25 20:02  御绫军TM_Sharweek  阅读(69)  评论(0)    收藏  举报