首页 > 其他分享 >洛谷 P2387 [NOI2014] 魔法森林 题解【动态加点 SPFA】

洛谷 P2387 [NOI2014] 魔法森林 题解【动态加点 SPFA】

时间:2022-10-09 08:56:18浏览次数:94  
标签:加边 洛谷 P2387 int 题解 加点 SPFA include 动态

题目大意

给定一个由 \(n\) 个点 \(m\) 条边的无向图,每条边有权值 \((a,b)\),求一条路径使这条路径上的 \((a_{\max}+b_{\max})\) 最小。

思路

正解应该是 LCT 动态维护 MST,本篇题解介绍一种“歪解”——动态加点 SPFA

我们先只考虑一个权值,那么这就是最单纯的最短路,跑一遍 SPFA 即可。

考虑有两个权值,我们可以从小到大枚举 \(a\),每次加边之后对 \(b\) 跑一遍 SPFA,若答案被更新,那么贡献一定是新加的 \(a\) 产生的。

由于我们不断加边,如果新加的边对答案有影响,那么 SPFA 时必然经过了这条边的两个端点。因此我们使用动态加点 SPFA,每次新加一条边之后将这条边的两个端点放入队列,然后更新全图的答案。

优化

  • 为保证单调性以及时间复杂度,我们不对 \(dis\) 数组更新。
  • 把 \(a\) 排序后枚举,随 \(a\) 权值递增而加边。

代码

//P2387 [NOI2014] 魔法森林
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int MAXN=5e4+10,MAXM=1e5+10,INF=0x3f3f3f3f;
struct Node
{
    int to,a,b;
};
struct Edge
{
    int from,to,a,b;
    bool operator <(Edge y)const
    {
        return a<y.a;
    }
}e[MAXM];
int n,m,dis[MAXN],ans=INF;
bool vis[MAXN];
queue<int> q;
vector<Node> g[MAXN];
void SPFA(int a)
{
    int u;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        vis[u]=false;
        for(Node v:g[u])
        {
            if(max(dis[u],v.b)<dis[v.to])
            {
                dis[v.to]=max(dis[u],v.b);
                if(!vis[v.to])
                {
                    q.push(v.to);
                    vis[v.to]=true;
                }
            }
        }
    }
    ans=min(ans,dis[n]+a);
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&e[i].from,&e[i].to,&e[i].a,&e[i].b);
    }
    sort(&e[1],&e[m+1]);
    fill(&dis[2],&dis[n+1],INF);
    for(int i=1,j;i<=m;i=j)
    {
        j=i;
        while(e[j].a==e[i].a)
        {
            g[e[j].from].push_back({e[j].to,e[j].a,e[j].b});
            g[e[j].to].push_back({e[j].from,e[j].a,e[j].b});
            q.push(e[j].from);
            q.push(e[j].to);
            vis[e[j].from]=vis[e[j].to]=true;
            j++;
        }
        SPFA(e[i].a);
    }
    printf("%d\n",(ans==INF?-1:ans));
    return 0;
}
/*
 * 洛谷
 * https://www.luogu.com.cn/problem/P2387
 * C++20 -O0
 * 2022.10.9
 */

附录

  1. 一些其他的非必要的优化:对 \(a\) 去重,Dijkstra 实现的堆优化等,参见 https://blog.csdn.net/Vmurder/article/details/39007471
  2. 本题动态加边 LCT 维护 MST 的做法,参见 https://blog.csdn.net/ylsoi/article/details/79863161

标签:加边,洛谷,P2387,int,题解,加点,SPFA,include,动态
From: https://www.cnblogs.com/2020gyk080/p/16770921.html

相关文章

  • LeetCode 字符串相乘算法题解 All In One
    LeetCode字符串相乘算法题解AllInOnejs/ts实现字符串相乘jsbignumbermultiply/js大数相乘字符串相乘原理&图解LeetCode43.MultiplyStringsLee......
  • R 包安装常见问题解决
    1.导读日常中使用R语言进行数据分析,或者画图的读者,相信一定逃不过的一个操作就是安装R包,那么在R包安装过程中,可能会出现一些问题,有时候这些问题并不是R包仓库下载过程中......
  • 【题解】sequence
    题意定义一个满足下列两个条件之一的序列\(a\)为单谷序列:\(\exists1\leqk\leqn\),有\(a_1<...<a_k>a_{k+1}>...>a_n\)\(\exists1\leqk\leq......
  • 2022洛阳师范学院ACM实验室招新竞赛题解
    A萌新签到题目描述欢迎大家来参加2022洛阳师范学院ACM实验室新生赛,我们实验室全体学长学姐从暑假一直期盼着你们的到来。我们的小萌新那么可爱,学长学姐肯定不会为难大......
  • P4967 黑暗打击 题解
    P4967黑暗打击题解目录P4967黑暗打击题解题目声明分析过程前置知识矩阵加速欧拉函数指数循环节转移矩阵推导利用指数循环节降低时间复杂度代码题目洛谷P4967黑暗......
  • maven打包提示子模块的程序包不存在问题解决
    有些utils和common的模块,已经有依赖,并能正常在Idea上跑了,但打包时提示程序包xxx不存在时,在pom上加上以下代码即可:<build><plugins><plugin><......
  • TypeError: cli.init is not a function 问题解决
    一、问题对于新手来说,新建一个Reactnative工程时可能会出现如下问题比如在命令行中输入:react-nativeinitchapter2就会报如下错误:这导致工程创建失败,里面仅有node_m......
  • [题解] Codeforces Dytechlab Cup 2022 1737 A B C D E 题解
    傻*Dytechlab还我rating!(不过目前rating还没加上去,据说E是偷的说不定要unrated)实在没预料到会打成这样。。。求点赞点我看题A.ElaSortingBooks从前往后一位一位确......
  • P4392 [BOI2007]Sound 静音问题 题解
    用树状数组维护区间最值,然后求和即可。//P4392[BOI2007]Sound静音问题#include<iostream>#include<cstdio>#include<vector>usingnamespacestd;constintINF......
  • scanf安全问题解决:
    1.加#define_CRT_SECURE_NO_WARNINGS  //必须写在程序的首句2.加#pragmawarning(disable:4996)       //可以写到任意位置 3.将scanf改为scanf_s......