写90分(省选数据100分)时写挂了,单向边加成双向边233.
很明显,最近的两个点,二进制某一位一定不同。
所以我们依靠二进制的每一位分成A,B组,超级源点连A,B连超级汇点,边权均为0。
然后最短路就是A,B之间的最短路。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5e5+5;
struct edge{
int v,w;
edge(int a=0,int b=0):v(a),w(b){}
};
vector<edge> e[maxn];
bool is[maxn];
int dis[maxn],n,T,m,k;
int dij(int s,int t){
memset(dis,0x3f3f3f3f3f3f3f3f,sizeof(dis));
dis[s]=0;
priority_queue<pair<int,int> > q;
q.push(make_pair(0,s));
while(!q.empty()){
int u=q.top().second,d=q.top().first;
q.pop();
for(auto E:e[u]){
int v=E.v,w=E.w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(make_pair(-dis[v],v));
}
}
}
return dis[t];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m>>k;
memset(is,0,sizeof(is));
for(int i=0;i<=n+1;i++)e[i].clear();
for(int i=1;i<=m;i++){
int x,y,w;
cin>>x>>y>>w;
e[x].push_back((edge){y,w});
}
for(int i=1;i<=k;i++){
int x;cin>>x;
is[x]=1;
}
int Min=0x3f3f3f3f3f3f3f3f;
for(int i=0;(1ll<<i)<=n;i++){
for(int j=1;j<=n;j++){
if(is[j]){
if(j&(1ll<<i))e[0].push_back(j);
else e[j].push_back(n+1);
}
}
Min=min(Min,dij(0,n+1));
for(int j=1;j<=n;j++){
if(is[j]){
if(!(j&(1ll<<i)))e[j].pop_back();
}
}e[0].clear();
for(int j=1;j<=n;j++){
if(is[j]){
if(j&(1ll<<i))e[j].push_back(n+1);
else e[0].push_back(j);
}
}
Min=min(Min,dij(0,n+1));
for(int j=1;j<=n;j++){
if(is[j]){
if(j&(1ll<<i))e[j].pop_back();
}
}e[0].clear();
}
cout<<Min<<endl;
}
return 0;
}