Loading

abc416e

AtCoder ABC416 E Development

link

题意

给定一张 \(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);
    }
  }
}
posted @ 2025-08-27 09:44  jess1ca1o0g3  阅读(6)  评论(0)    收藏  举报