嘘~ 正在从服务器偷取页面 . . .

CF1343E Weights Distributing 题解


CF1343E Weights Distributing 题解

题目链接:CF1343E Weights Distributing

题意

给出一个有 \(n\) 个点,\(m\) 条边的无向图和一个长为 \(m\) 的权值序列 \(w\)

你可以随意安排边权(每条边权对应 \(w\) 中的一个数,不可以重复)。

\(a\)\(b\) 的最短路与 \(b\)\(c\) 的最短路的和的最小值。

输入格式

多组数据。每次给出 \(n,m,a,b,c\) 。第一行给出 \(n\) 个整数 \(w_i\) 。接下来 \(m\) 行给出边 \((u,v)\)

输出格式

对于每组数据,输出最小值。

数据范围

\(1\le n-1 \le m \le \min\left\{\frac{n(n-1)}{2},~2\times 10^5\right\},~1 \le \sum n,\sum m \le 2 \times 10^5,~ 1 \le w_i \le 10^9\)

注意到 \(a\leadsto b\)\(b \leadsto c\) 的最短路径可能重合,会有一些边被算两遍。

根据贪心的思想,我们会优先把小的边分配给他们。

但是这个重合的路径怎么找呢?

一个错误的做法是直接找两条最短路径的交集,反例懒得构造,很容易卡。

答案是枚举一个 \(d\) ,然后答案就是 \[ \mathtt{dis}(a,d) + 2\times\mathtt{dis}(b,d) + \mathtt{dis}(d,c) \] 因为边权是可以自己加的,所以我们用 \(\mathtt{bfs}\) 把边权当成 \(1\) 预处理一下最少经过几条边啥的,具体看代码。

单组数据时间复杂度 \(\mathcal{O}(n + m \log m)\) ,瓶颈在排序。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5+15))

int n,m,A,B,C,pos=1,head[N],w[N],sum[N],da[N],db[N],dc[N];
struct Edge { int u,v,next; } e[N * 2];
void addEdge(int u,int v) { e[++pos] = {u,v,head[u]}; head[u] = pos; }
queue<int> q;
void solve(int st,int *d)
{
    for(int i=1; i<=n; i++) d[i] = INF;
    d[st] = 0; while(!q.empty()) q.pop();
    for(q.push(st); !q.empty(); )
    {
        int u = q.front(); q.pop();
        for(int i=head[u]; i; i=e[i].next)
        {
            int v = e[i].v;
            if(d[v] == INF) { d[v] = d[u] + 1; q.push(v); }
        }
    }
}
void clear()
{ pos = 1; for(int i=1; i<=n; i++) head[i] = 0; }
void work()
{
    clear(); cin >> n >> m >> A >> B >> C;
    for(int i=1; i<=m; i++) cin >> w[i];
    sort(w + 1, w + 1 + m);
    for(int i=1; i<=m; i++) sum[i] = sum[i-1] + w[i];
    for(int i=1,u,v; i<=m; i++)
    { cin >> u >> v; addEdge(u,v); addEdge(v,u); }
    solve(A,da); solve(B,db); solve(C,dc);
    int res = INF;
    for(int i=1,a,b,c; i<=n; i++)
    {
        a = da[i], b = db[i], c = dc[i];
        if(a + b + c <= m) down(res, sum[a + b + c] + sum[b]);
    }
    cout << res << '\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int _Q; cin >> _Q; while(_Q--) work();
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录