P5304 [GXOI/GZOI2019]旅行者

写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;
}

P5304 [GXOI/GZOI2019]旅行者

上一篇:vuex 简易版实现


下一篇:iproute2 高级流量控制