D 自由世界

思路很简单,先给每个点跑一遍最短路,记录的路径长度。再去管传送门,从每个传送门这跑一遍最短路,记录传送门到的路径取个最小值即可。

我一开始为了图个方便,把传送门和每个点都建了个边权为的边,导致凭空多出来至少条边,就T了,呜呜呜。。。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+10;
const int inf=0x3f3f3f3f;
struct sa{
    int dis;
    int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }

priority_queue<sa>q;


struct Edge
{
    int u, v, w, next;
}edge[N<<2];
int head[N];
int cnt;
void add_edge(int u, int v, int w)
{
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}


int dis[N];
bool vis[N];
int n,m,s,t,u,v,w,T,k;

void dij(int s,int v,int d[]){
    memset(vis,0,sizeof(vis));
    for (int i=1;i<=n;i++) d[i] = inf;
    d[s]=v;
    q.push( (sa) {v,s});
    while(!q.empty())
    {
        sa ns=q.top();
        q.pop();
        int x=ns.pos;
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x]; i!=-1 ; i=edge[i].next)
        {
            int to=edge[i].v;
            int dd=d[x]+edge[i].w;
            if(d[to]>dd)
            {
                d[to]=dd;
                q.push( (sa) {d[to],to});
            }
        }
    }
}
int cnt1[N];
int main()
{

    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 1 ;i <= m ;i++){
        scanf("%d%d%lld",&u,&v,&w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    for(int i = 1 ;i <= n - 1 ;i++){
        dij(i, 0, dis);
        cnt1[i + 1] = dis[i + 1];
    }
    for(int i = 1 ;i <= k; i++){
        scanf("%d",&u);
        dij(u , 0 , dis);
        for(int j = 1 ;j <= n - 1; j++){
           cnt1[j + 1] = min( cnt1[j + 1] , dis[j + 1]);
        }
    }
    long long ans = 0;
    for (int i = 2; i <= n; i++) {
        ans += cnt1[i];
    }
    printf("%lld",ans);
    return 0;
}