[ABC416]E-Development解题报告

前言

赛时这题交了三发,都被卡了,最终止步于rk3248 QwQ

问题简述

动态维护一张无向图,支持修改,计算所有点对的最短路径总和。原题链接

切入

看到 \(N \leq 500\) 很容易想到使用 \(Floyd_Warshall\) 来对整张图进行一个 \(O(N^3)\) 的遍历来统计各个点之间的最短路
对于机场而言,我们可以用一个桶来维护,在遍历每个点的时候单独判断是否有机场,然后对边权与t进行比较
显然对于每次 \(opt=3\) 的询问我们都要做一次 \(Floyd\) ,总时间复杂度就是 \(O(pN^3)\) \(p\)代表\(q\)\(opt=3\) 的次数
这样的时间复杂度在 \(p\) 很大时是无法接受的,最多只能过掉7个点

优化

我们发现, \(O(N^3)\) 询问的效率太低了,对于每次建边,可以把u和v单独拿出来进行 \(Floyd\)
对于机场而言,可以建一个键值为 \(N+1\) 的天空中转点,从机场到天空的边权为 \(t\) ,从天空到机场的边权为 \(0\) ,将天空和机场的点拿出来进行 \(Floyd\)
这样,我们便有了一个均匀的为 \(O(N^3+qN^2)\) 的复杂度,足够过掉此题
AC Code

点击查看代码
// Problem: E - Development
// Contest: AtCoder - AtCoder Beginner Contest 416
// URL: https://atcoder.jp/contests/abc416/tasks/abc416_e
// Memory Limit: 1024 MB
// Time Limit: 3500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long 
#define endl '\n'
#define endll " "
#define it inline int
#define iv inline void
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#pragma GCC optimize(0)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int MAXN=510;
const int INF=1e18;
const int mod=998244353;
it gcd(int x,int y){return y==0?x:gcd(y,x%y);}
it lcm(int x,int y){return x/gcd(x,y)*y;}
it max(int x,int y){return x>y?x:y;}
it min(int x,int y){return x<y?x:y;}
it qpow(int x,int m,int mod) 
{
    int res=1,bas=x%mod;
    while(m)
    {
        if(m&1) res=(res*bas)%mod;
        bas=(bas*bas)%mod,m>>=1;
    }
    return res%mod;
}
int n,m,u,v,w,k,t,q,opt,x,y,dis[MAXN][MAXN];
bool f[MAXN];
it query() 
{
    int res=0;
    for(int i=1;i<=n;i++) 
	{
        for(int j=1;j<=n;j++)
		 {
            if(dis[i][j]!=INF)
                res+=dis[i][j];
        }
    }
    return res;
}
iv update(int k)
{
	for(int i=1;i<=n+1;i++) 
    {
         if(dis[i][k]==INF) 
         	continue;
        for(int j=1;j<=n+1;j++) 
        {
              if(dis[k][j]!=INF && dis[i][j]>dis[i][k]+dis[k][j])
                dis[i][j]=dis[i][k]+dis[k][j];
        }
    }
}
signed main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0); 
	cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n+1;i++) 
        for(int j=1;j<=n+1;j++) 
            dis[i][j]=(i==j)?0:INF;
    for(int i=1;i<=m;i++) 
	{
        cin>>u>>v>>w;
        if(w<dis[u][v]) 
		{
            dis[u][v]=w;
            dis[v][u]=w;
        }
    }
    cin>>k>>t;
    for(int i=1;i<=k;i++) 
	{
        cin>>x;
		f[x]=1;
        dis[x][n+1]=t; 
        dis[n+1][x]=0; 
    }
    for(int k=1;k<=n+1;k++) 
	{
        for(int i=1;i<=n+1;i++) 
        {
            if(dis[i][k]==INF) 
            	continue;
            for(int j=1;j<=n+1;j++) 
            {
                if(dis[k][j]!=INF && dis[i][j]>dis[i][k]+dis[k][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
            }
        }
    }
    cin>>q;
    while(q--) 
	{
        cin>>opt;
        if(opt==1) 
		{
            cin>>u>>v>>w;
            if(w>=dis[u][v]) 
				continue;  //只有当新路更短时才更新
            dis[u][v]=w;
            dis[v][u]=w;
            update(u);
            update(v);
        }
        if(opt==2) 
		{
            cin>>x;
			if(f[x]==1)
				continue;
			f[x]=1;
            dis[x][n+1]=t;
            dis[n+1][x]=0;
            update(x);
            update(n+1);
        }
        if(opt==3) 
		{
            cout<<query()<<endl;
        }
    }
    return 0;
}
posted @ 2025-07-30 10:31  KLaneX  阅读(16)  评论(0)    收藏  举报