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;
}
posted @ 2020-06-07 21:42  Handlip  阅读(109)  评论(0)    收藏  举报