abc416e
AtCoder ABC416 E Development
题意
给定一张 \(n\) 个点 \(m\) 条边的无向图,边 \((a_i,b_i)\) 有边权 \(c_i\)。其中有 \(k\) 个特殊点,特殊点之间两两有 \(t\) 的边。\(q\) 次操作,加一条边,新指定一个特殊点,求出 \(\sum_{i=1}^n\sum_{j=1}^n f(i,j)\),其中 \(f_{i,j}\) 表示 \(i\) 到 \(j\) 的最短路。\(n\leq 500,m\leq 10^5,q\leq 1000,1\leq 边权\leq 10^9\)。
题解
很显然最开始可以 Floyd 跑全源最短路,得到初始两个点的距离。考虑加边操作,比较简单,直接枚举 \(i,j\) 必须通过新边的最短路来尝试更新。指定特殊点比较难,因为每加一个点都会和原来的点连边,不可接受。建一个虚点 \(0\),所有特殊点都和 \(0\) 连,然后更新一下。最后统计答案就直接暴力枚举即可。复杂度 \(O(n^3+qn^2)\)。aclink。
坑
- 开
long long。
代码
#include<bits/stdc++.h>
#define i64 long long
#define L(a,b,c,d) for(int a=b;a<=c;a+=d)
#define R(a,b,c,d) for(int a=b;a>=c;a-=d)
using namespace std;
const int N=505;
void solve();
int n,m,k,q;
i64 t,f[N][N];
signed main(){
int Test=1;
// scanf("%d",&Test);
while(Test--) solve();
return 0;
}
void solve(){
scanf("%d%d",&n,&m);
L(i,0,n,1){
L(j,0,n,1) f[i][j]=1e18;
}
L(i,0,n,1) f[i][i]=0;
L(i,1,m,1){
int x,y;
i64 z;
scanf("%d%d%lld",&x,&y,&z);
f[x][y]=min(f[x][y],z);
f[y][x]=min(f[y][x],z);
}
scanf("%d%lld",&k,&t);
L(i,1,k,1){
int x;
scanf("%d",&x);
f[x][0]=min(f[x][0],t);
f[0][x]=0;
}
L(k,0,n,1){
L(i,0,n,1){
L(j,0,n,1){
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
}
}
scanf("%d",&q);
while(q--){
int op;
scanf("%d",&op);
if(op==1){
int x,y;
i64 z;
scanf("%d%d%lld",&x,&y,&z);
L(i,0,n,1){
L(j,0,n,1){
f[i][j]=min({f[i][j],f[i][x]+z+f[y][j],f[i][y]+z+f[x][j]});
}
}
}
else if(op==2){
int x;
scanf("%d",&x);
L(i,0,n,1){
L(j,0,n,1){
f[i][j]=min({f[i][j],f[i][x]+t+f[0][j],f[i][0]+f[x][j]});
}
}
}
else{
i64 ans=0;
L(i,1,n,1){
L(j,1,n,1){
if(f[i][j]<1e18) ans+=f[i][j];
}
}
printf("%lld\n",ans);
}
}
}
本文来自博客园,作者:jess1ca1o0g3,转载请注明原文链接:https://www.cnblogs.com/jess1ca1o0g3/p/19060328

浙公网安备 33010602011771号