题解: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;
}

浙公网安备 33010602011771号