题解 「JOI 2021 Final」ロボット / Robot
考虑从
- 将该边改为一种不冲突的颜色,费用
w 。 - 将所有相同颜色的其他边改掉,费用
S_{u,c}-w 。
发现
发现若有
考虑建立虚点
于是跑 Dijkstra 即可。
最多每条边都建一个虚点,故点数是
注意:以下参考代码大量使用 STL 和 C++17 特性,常数巨大且需要注意编译选项(亲测 std::map 比 std::unordered_map 快)。
const int N = 100005;
void addedge(int u, int v, int c, int w);
std::map<int, ll> sum[N], dis[N];
std::map<int, int> len[N], col[N];
std::map<int, std::vector<pii>> mp[N];
int n, m;
int main() {
read(n), read(m);
for (int i = 1; i <= m; ++i) {
int u, v, c, w;
read(u), read(v), read(c), read(w);
addedge(u, v, c, w), addedge(v, u, c, w);
}
std::priority_queue<std::tuple<ll, int, int>> pq;
auto upd = [&](int v, int c, ll udis) {
if (!dis[v].count(c) || dis[v][c] > udis) {
dis[v][c] = udis;
pq.emplace(-udis, v, c);
}
};
upd(1, 0, 0);
while (!pq.empty()) {
auto [d, u, c] = pq.top();
d = -d;
pq.pop();
if (d != dis[u][c]) continue;
for (auto [v, vc] : mp[u][c]) {
ll w;
if (c == vc)
w = std::min(1ll * len[u][v], sum[u][col[u][v]] - len[u][v]);
else if (c)
w = sum[u][c] - len[u][v];
else
w = 0;
upd(v, vc, d + w);
}
}
if (dis[n].count(0))
write(dis[n][0]), EL;
else
puts("-1");
return 0;
}
void addedge(int u, int v, int c, int w) {
col[u][v] = c, len[u][v] = w;
sum[u][c] += w;
mp[u][0].emplace_back(v, 0);
mp[u][0].emplace_back(v, c);
mp[u][c].emplace_back(v, 0);
}