专栏文章

题解:AT_abc416_e [ABC416E] Development

AT_abc416_e题解参与者 27已保存评论 28

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
28 条
当前快照
1 份
快照标识符
@mltblyl3
此快照首次捕获于
2026/02/19 18:30
3 周前
此快照最后确认于
2026/02/19 18:30
3 周前
查看原文

思路

蒟蒻第一篇绿题题解,求管理一定要给过呀。
相信大家都学过最短路吧。没学过也没关系。
我来讲一讲多源最短路的 Floyd 算法。
其实本质上就是 DP,我们创建一个数组 aa,设 ai,ja_{i,j} 为从城市 ii 出发到城市 jj 结束的最少时间。
当我们在连完所有的双向道路后,可以进行一下一系列操作。
CPP
for(int k=1;k<=501;k++)
for(int i=1;i<=501;i++)
for(int j=1;j<=501;j++)
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
我们首先枚举这个点 kk,点 kk 为中转点,然后分别枚举 iijj,此时如果 iijj 的时间比 ii 先到 kk 再到 jj 的时间长,那么我们就把 iijj 的最短时间更新为 iikk 的最短时间与 kkjj 的最短时间和。
注意先枚举中转点 kk 哈,我就卡在这里卡了很久。
那么,对于从 xxyy 新加入一条边怎么处理呢?如果全部重新处理一下(即复制一遍上边代码),那复杂度可以达到 O(Q×n3)O(Q\times n^3) 的,此题的数据无法接受。
我们发现,只有中转点同时带有 xxyy 的点才有可能发生改变。此时,我们枚举 iijj,如果 ii 先到 xx 再到 yy 再到 jj 的时间比原有时间更少,更新求值。
如果 ii 先到 yy 再到 xx 再到 jj 的时间比原有时间更少,也更新求值(特别注意!我在这里也卡了好久)。
然后见代码,至于为什么 zz×2\times 2,后文会说的。
CPP
cin>>x>>y>>z;
jl=z*2;
a[x][y]=min(a[x][y],jl);
a[y][x]=min(a[y][x],jl);
for(int i=1;i<=501;i++)
for(int j=1;j<=501;j++)
a[i][j]=min(a[i][j],a[i][x]+a[x][y]+a[y][j]),a[i][j]=min(a[i][j],a[i][y]+a[y][x]+a[x][j]);
下面讲重点了!对于机场怎么处理呢?很难空想想出来,这是基于我大量的刷题才可灵光一现的。
我突然发现我们可以再设立一个点,然后每一个有机场的边都对这一个点连一半的时间,最后所有的机场之间不就是两个一半也就是完整的 tt 了吗。
但是,由于浮点数不好处理,所以我们就把所有的边都 ×2\times 2 再连接,最后统计答案时除回来就可以了。
对于统计答案,就好说了。
我们只要枚举一下 iijj,然后对 ai,ja_{i,j} 加和,最后 ÷2\div 2 即可。
最后,警告一下不开 long long 见祖宗。
若有哪里没听懂,欢迎私信问。

代码

CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,q,k,t,x,y,z,a[505][505],jl,o;
signed main(){
    cin>>n>>m;
    for(int i=1;i<=501;i++)
    for(int j=1;j<=501;j++){
        if(i==j)a[i][j]=0;
        else a[i][j]=1e18;
    }
    for(int i=1;i<=m;i++){
        cin>>x>>y>>z;
        jl=z*2;
        a[x][y]=min(a[x][y],jl);
        a[y][x]=min(a[y][x],jl);
    }
    cin>>k>>t;
    while(k--)cin>>x,a[x][501]=t,a[501][x]=t;
    for(int k=1;k<=501;k++)
    for(int i=1;i<=501;i++)
    for(int j=1;j<=501;j++)
    a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
    cin>>q;
    while(q--){
        cin>>o;
        if(o==1){
            cin>>x>>y>>z;
            jl=z*2;
            a[x][y]=min(a[x][y],jl);
            a[y][x]=min(a[y][x],jl);
            for(int i=1;i<=501;i++)
            for(int j=1;j<=501;j++)
            a[i][j]=min(a[i][j],a[i][x]+a[x][y]+a[y][j]),a[i][j]=min(a[i][j],a[i][y]+a[y][x]+a[x][j]);
        }
        else if(o==2){
            cin>>x;
            a[x][501]=t;
            a[501][x]=t;
            for(int i=1;i<=501;i++)
            for(int j=1;j<=501;j++)
            a[i][j]=min(a[i][j],a[i][x]+a[x][501]+a[501][j]),a[i][j]=min(a[i][j],a[i][501]+a[501][x]+a[x][j]);
        }
        else if(o==3){
            jl=0;
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            if(a[i][j]!=1e18)jl+=a[i][j];
            cout<<jl/2<<endl;
        }
    }
}


评论

28 条评论,欢迎与作者交流。

正在加载评论...