CF1343E Weights Distributing
题目
给你一张 \(n\) 个点 \(m\) 条边的无向图,以及 \(m\) 个数 \(a_1,a_2, \cdots ,a_m\)。有一个人要从 \(a\) 点走到 \(b\) 点,再从 \(b\) 点走到 \(c\) 点。你需要将 \(a_1,a_2, \cdots ,a_m\) 与每条边的边权一一对应,使得这个人所走的最短路径最小,求最小值是多少。
数据范围
\(n,m \le 2 \cdot 10^5\)
限制
时间:2s
空间:256M
代码
# include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX1 = 2e5 + 5;
const int MAX2 = 4e5 + 5;
const ll INF = 1e18;
struct Graph
{
int n, m;
int to[MAX2], next[MAX2];
int head[MAX1], dis[3][MAX1];
queue<int> q;
void init()
{
m = 0;
memset(head + 1, 0, sizeof(int) * n);
}
void add(int u, int v)
{
to[++m] = v;
next[m] = head[u];
head[u] = m;
}
void bfs(int start, int x)
{
memset(dis[x] + 1, -1, sizeof(int) * n);
dis[x][start] = 0;
q.push(start);
while (!q.empty())
{
int cur = q.front();
q.pop();
for (int i = head[cur]; i; i = next[i])
{
if (dis[x][to[i]] == -1)
{
dis[x][to[i]] = dis[x][cur] + 1;
q.push(to[i]);
}
}
}
}
} g;
int n, m, x, y, z;
ll a[MAX1], sum[MAX1];
void init()
{
memset(sum + 1, 0, sizeof(ll) * m);
}
ll f(int x, int y)
{
return sum[y] - sum[x - 1];
}
int main()
{
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d %d %d %d %d", &n, &m, &x, &y, &z);
g.n = n;
init();
g.init();
for (int i = 1; i <= m; ++i)
{
scanf("%lld", &a[i]);
}
int u, v;
for (int i = 0; i < m; ++i)
{
scanf("%d %d", &u, &v);
g.add(u, v);
g.add(v, u);
}
sort(a + 1, a + m + 1);
for (int i = 1; i <= m; ++i)
{
sum[i] = sum[i - 1] + a[i];
}
g.bfs(x, 0);
g.bfs(y, 1);
g.bfs(z, 2);
ll ans = INF;
for (int i = 1; i <= n; ++i)
{
int tmp = g.dis[0][i] + g.dis[1][i] + g.dis[2][i];
if (tmp <= m)
{
ans = min(ans, f(1, g.dis[1][i]) * 2 + f(g.dis[1][i] + 1, tmp));
}
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号