首页 > 其他分享 >[NOIP2013 提高组] 货车运输 题解

[NOIP2013 提高组] 货车运输 题解

时间:2022-12-29 08:55:34浏览次数:39  
标签:qs NOIP2013 int 题解 货车运输 fa ans include find

[NOIP2013 提高组] 货车运输 题解

本题解介绍一种 最大生成树+并查集+启发式合并离线 的做法。

想法

题目要多次求两点之间的最大瓶颈路长度,所以可以先参照最小瓶颈路的通常求法构造出一个最大生成树,这样在这棵最大生成树上的任意两点之间的距离即为它们最大瓶颈路的距离。

在此处出现了许多做法,可以使用 \(\text{LCA}\) 快速求解这个树上问题,不过其实还有一种新奇的思路。

思路

考虑在 \(\text{Kruskal}\) 算法求解最大生成树的时候,把询问离线地挂在点上,如果在 \(\text{merge(a, b)}\) 操作的时候发现 \(a\) 所在的集合中有合并是到 \(b\) 所在的集合的,且之前没有处理过,那么此时一定是最优解,直接把此次合并操作的边权 \(w_{a\rightarrow b}\) 置为那次询问的结果。

如果只是朴素做法的话这道题中会超时,可以考虑采用启发式合并——把询问次数少的集合合并到询问次数多的集合中,进行优化。

总时间复杂度:\(O(m\log m + q)\)。

// Problem: P1967 [NOIP2013 提高组] 货车运输
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1967
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Moyou
// Copyright (c) 2022 Moyou All rights reserved.
// Date: 2022-12-26 20:15:07

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;

const int N = 1e4 + 10, M = 1e5 + 10, Q = 3e4 + 10;

struct qwq
{
    int a, b, c;
} edge[M];

int read(){...}

int fa[N], ans[Q];
vector<PII> qs[N]; // 点上的查询
int find(int x)
{
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

void merge(int a, int b, int w)
{
    int x = find(a), y = find(b);
    if (x == y)
        return;
    if (qs[x].size() > qs[y].size())
        swap(x, y);
    fa[x] = y;
    for (auto i : qs[x])
    {
        int j = i.x, id = i.y;
        if (~ans[id]) // 已经有解了不用更新,即使此次有解也肯定没有之前的优
            continue;
        if (find(j) == y) // 如果此次有解
            ans[id] = w; // 将查询置为这个解
    }
    for (auto i : qs[x]) // 合并查询
        if(!~ans[i.y])
            qs[y].push_back(i);
}

int main()
{
    memset(ans, -1, sizeof ans);
    int n = read(), m = read();
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    for (int i = 1; i <= m; i++)
    {
        int a = read(), b = read(), c = read();
        edge[i] = {a, b, c};
    }
    sort(edge + 1, edge + m + 1, [](qwq a, qwq b) { return a.c > b.c; }); // 从大到小排序
    int q = read();
    for (int i = 1; i <= q; i++)
    {
        int a = read(), b = read();
        qs[a].push_back({b, i});
        qs[b].push_back({a, i});
    }
    for (int i = 1; i <= m; i++)
        merge(edge[i].a, edge[i].b, edge[i].c);
    for (int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
        
    return 0;
}

标签:qs,NOIP2013,int,题解,货车运输,fa,ans,include,find
From: https://www.cnblogs.com/MoyouSayuki/p/17011668.html

相关文章

  • LeetCode 寻找数组的中心下标算法题解 All In One
    LeetCode寻找数组的中心下标算法题解AllInOne724.FindPivotIndex寻找数组的中心下标"usestrict";/****@authorxgqfrms*@licenseMIT*@copyr......
  • Cordforces 1774D题解
    题目链接:https://codeforces.com/problemset/problem/1774/DDescription:给定n个长为m的二进制串,每次可以选出任意两个,然后交换这两个二进制串同一列的数。求最少的操作......
  • [题解] CF1761E Make It Connected
    CF1761EMakeItConnected题目大意给一张无向图,每次操作表现为选择一个点\(x\),断开所有原来连上的边,连接所有原来断开的边。求最少需要几步使得图联通,并构造方案。思......
  • LOJ 6041 「雅礼集训 2017 Day7」事情的相似度 题解 (SAM+启发式合并)
    题目链接首先很容易想到的是对反串求SA和LCP,然后询问就是求起点在某个区间内的所有后缀两两LCP的最大值,可以用莫队解决,时间复杂度\(O(n\sqrtnlogn)\),应该是过不了的。......
  • P5137 题解
    前言首先感谢所有帮助我卡常的大佬们。题意求\((\sum_{i=0}^{n}a^ib^{n-i})\modp\)的值(\(n\leq10^{18}\),\(p\)不一定为质数)。分析看到数据范围,首先想到快......
  • C#提示指定的路径或文件名太长问题解决办法
    我用的是.net4.0的环境,直接在app.config配置文件中加几行配置就行。如下图:<configuration><runtime><AppContextSwitchOverridesvalue="Switch.System.IO.......
  • SEERC2022 D Divisible by 4 Spanning Tree 题解
    题意给定\(n\)个点\(m\)条边的无向连通图,判断是否有存在生成树满足:度数为奇数的点个数为\(4\)的倍数。\(1\len\le200000,1\lem\le400000\)题解度数总和是\(2n......
  • 【题解】P5298 [PKUWC2018]Minimax
    P5298[PKUWC2018]Minimax思路线段树合并优化树形dp.值域1e9首先考虑离散化。然后发现需要维护每种权值的出现概率,于是可以考虑到一个简单的树形dp:设\(f[i][j]\)......
  • 问题解决:Failed to download metadata for repo ‘appstream‘: Cannot prepare inter
    https://cloud.tencent.com/developer/article/1993317 大家都知道Centos8于2021年年底停止了服务,大家再在使用yum源安装时候,出现下面错误“错误:Failedtodownloadmet......
  • 快速幂 矩阵快速幂题解
    目录快速幂矩阵快速幂练习题题解12.28HDU1061HDU1575HDU2035HDU5015HDU6198快速幂矩阵快速幂练习题题解12.28HDU1061题意:给定T组数据,接下来T行有T个数,求N的N次......