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

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

时间:2024-04-02 12:33:06浏览次数:21  
标签:int 题解 边权 LCA 货车运输 生成 fa ans P1967

P1967 [NOIP2013 提高组] 货车运输

原题地址

思路:

由于题目要求的是使两点之间的最小边权最大,所以可以构造最大生成树(最大生成树一定是最大瓶颈生成树,而瓶颈生成树上两点之间的路径,在原图中的所有路径中,最小边权仍然最大,即满足题目要求,详见 https://oi-wiki.org/graph/mst/#性质 ),答案为最大生成树上的路径的最小边权。

求树上路径上的边权最值可以使用 \(LCA\),因为它可以通过合并两个点的 \(LCA\) 和这两个点到 \(LCA\) 的路径的边权最值得来。

做法:

先用 \(Kruskal\) 算出最大生成树,再用倍增的方式计算 \(LCA\),并维护每条路径上的最小边权。

\(e\) 表示初始图,\(G\) 表示最大生成树,\(deep\) 表示点的深度,\(fa_{i,j}\) 表示 \(i\) 的第 \(2^j\) 级祖先,\(w_{i,j}\) 表示 \(i\) 到 \(i\) 的第 \(2^j\) 级祖先的路径上的最小边权,在求 \(LCA\) 的过程中输出经过的点上的最小边权即可。

代码:

时间复杂度:\(\Theta(m\log m + n\log n)\)

#include<iostream>
#include<vector>
#include<algorithm>
#define int long long
using namespace std;

const int N = 10010;
const int E = 50010;
const int M = 25;
const int INF = 1e18;

struct Node { int v, w; } ;
struct Edge { int u, v, w; } ;

int n, m, q;
int f[N], fa[N][M], deep[N], w[N][M];
bool vis[N];
Edge e[E];
vector<Node> G[N];

// 排序初始边,用于求最大生成树
bool cmpk(Edge x, Edge y) { return x.w > y.w; } 

int find(int x) // 并查集 - 查找祖先
{
    if(f[x] == x)
        return f[x];
    return f[x] = find(f[x]);
}

void kruskal() // 求最大生成树
{
    sort(e+1, e+m+1, cmpk);
    for(int i=1; i<=n; i++)
        f[i] = i;
    for(int i=1; i<=m; i++)
    {
        int u = e[i].u, v = e[i].v, w = e[i].w;
        if(find(u) == find(v))
            continue;
        f[find(u)] = find(v);
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
}

void predfs(int u) // LCA初始化1 - 求出深度、父亲
{
    vis[u] = true;
    for(int i=0; i<G[u].size(); i++)
    {
        int v = G[u][i].v;
        if(vis[v])
            continue;
        deep[v] = deep[u] + 1;
        fa[v][0] = u;
        w[v][0] = G[u][i].w;
        predfs(v);
    }
}

int LCA(int x, int y) // 求LCA和答案
{
    if(find(x) != find(y))
        return -1;
    int ans = INF;
    if(deep[x] > deep[y])
        swap(x, y);
    for(int i=20; i>=0; i--)
    {
        if(deep[fa[y][i]] < deep[x])
            continue;
        ans = min(ans, w[y][i]);
        y = fa[y][i];
    }
    if(x == y)
        return ans;
    for(int i=20; i>=0; i--)
    {
        if(fa[x][i] == fa[y][i])
            continue;
        ans = min(ans, min(w[x][i], w[y][i]));
        x = fa[x][i];
        y = fa[y][i];
    }
    ans = min(ans, min(w[x][0], w[y][0]));
    return ans;
}

void prelca() // LCA初始化2 - 求出祖先
{
    for(int i=1; i<=20; i++)
    {
        for(int j=1; j<=n; j++)
        {
            fa[j][i] = fa[fa[j][i-1]][i-1];
            w[j][i] = min(w[j][i-1], w[fa[j][i-1]][i-1]);
        }
    }
}

signed main()
{
    cin >> n >> m;
    for(int i=1; i<=m; i++)
        cin >> e[i].u >> e[i].v >> e[i].w;
    kruskal();
    for(int i=1; i<=n; i++)
    {
        if(vis[i])
            continue;
        deep[i] = 1;
        predfs(i);
        fa[i][0] = i;
        w[i][0] = INF;
    }
    prelca();
    cin >> q;
    while(q --)
    {
        int x, y; cin >> x >> y;
        cout << LCA(x, y) << '\n';
    }
    return 0;
}

标签:int,题解,边权,LCA,货车运输,生成,fa,ans,P1967
From: https://www.cnblogs.com/gctiruct/p/18110327

相关文章

  • Golang | Leetcode Golang题解之第4题寻找两个正序数组的中位数
    题目:题解:funcfindMedianSortedArrays(nums1[]int,nums2[]int)float64{iflen(nums1)>len(nums2){returnfindMedianSortedArrays(nums2,nums1)}m,n:=len(nums1),len(nums2)left,right:=0,mmedian1,median2:=0,0......
  • CF1935D Exam in MAC 题解
    ExaminMAC题意\(t\)组数据。给定一个大小为\(n\)的集合\(s\)和一个整数\(c\),保证\(0\leqslants_i\leqslantc(1\leqslanti\leqslantn)\)。求有多少对整数数对\((x,y)\),满足:\(0\leqslantx\leqslanty\leqslantc\)。\(x+y\notins\)且\(y-x\not......
  • 2024最新一线互联网大厂常见高并发面试题解析
    面试官:临界区是什么?答:临界区用来表示一种公共资源或者说是共享资源,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。比如,在一个办公室里有一台打印机,打印机一次只能执行一个任务。如果小王和小明同时需要打......
  • 【赛题解析】【移动应用开发】全国职业院校技能大赛任务一:实现社区首页功能解析
    ​培训、环境、资料、考证公众号:波比网络公众号2:波比网络工作室移动应用开发技能大赛交流群:548238632波比网络专注于技能提升,赋能**本文章全文由波比网络原创,非法转载必究!**文章目录移动应用与开发任务1:实现社区首页功能1.界面顶部显示所在社区名称、轮播图和社......
  • IDEA中新建SpringBoot模块,JDK版本问题解决
    问题描述IDEA中新建SpringBoot模块,使用的JAVAJDK1.8,新建模块时选项中没有JDK8: 运行时报错,JDK之类的问题解决方案,查看修改以下四个地方:(1)设置-Java编译器 (2)项目结构--依赖以及源码 ......
  • 哈尔滨理工大学3-31校赛模拟赛第一场题解
    概览:ABF为签到题,CE模拟,D深搜,G最短路,H双指针A.提取数字:注意前导零的情况需要排除,由于组成的数不超过longlong范围,所以直接用res承接就好了#include<iostream>usingnamespacestd;longlongres;intmain(){charc;while(cin>>c)if(c>='0'&&c<='9......
  • CCF CSP模拟真题解答示例
    CCFCSP(CertifiedSoftwareProfessional)是中国计算机学会主办的软件能力认证考试,旨在评估参赛者在计算机科学和软件工程方面的基本知识和实践能力。请注意,以下解答仅作为示例,并非针对实际真题的准确答案。实际考试中的题目和答案可能会有所不同,因此建议参考官方发布的真题......
  • 洛谷 P9907 [COCI 2023/2024 #1] Mostovi 题解
    题目分析首先可以确定的是需要枚举断边,所以我们希望两次枚举之间能有些关联。不难想到类树形DP的套路,建DFS树,只不过这题除了讨论和父亲之间的边,还要考虑返租边。以下钦定以\(1\)为树根。树边先从简单的树边开始考虑。考虑不经过\(u\)和\(u\)的父亲\(v\),对答案是否产......
  • ABC347F 题解
    我们考虑这三个正方形的相对位置有多少种情况。我们把正方形的顶点设为\((x_i,y_i)\)。容易发现,放置合法当且仅当\(\foralli\neqj,|\x_i-x_j\|\geqd\\text{or}|\y_i-y_j\|\geqd\)。发现这只有可能是以下两种情况。于是便可以开始写了。/***********......
  • 【题解】Codeforces 1942E - Farm Game
    题目链接:https://codeforces.com/contest/1942/problem/E题目大意:输入一个\(l\)和一个\(n\),其中\((1\leql\leq10^6,2n<=l)\),表示有\(l\)个不同的空位(分别是\([1,l]\))和\(2n\)头完全一样的牛。Alice和Bob分别有\(n\)头牛,并且他们的牛是间隔排列的。每一次......