习题:旅行者(dij&二进制&卡常)

题目

传送门

思路

这道题的k很大

但是我们要求的只是两个点之间的最短距离

于是可以建一个超级原点,

但是这个超级原点连接哪些点呢?

由于我们要求的是两个点

所以我们只需要在某一次dij中将两个点分开就行了

所以自然而然的想到二进制

将S连接第i位二进制为1的点跑一遍dij

再将S连接第i位二进制为0的店跑一遍dij就行了

有点轻微卡常,如果你需要稳一点,建议将代码中的优先队列换成手写的treap
我不做人啦,JOJO!

代码

#pragma GCC optimize(2)
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
void read(int &x)
{
	x=0;
	int f=1;
	char c=getchar();
	while('0'>c||c>'9')
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	x*=f;
}
void read(long long &x)
{
	x=0;
	long long f=1;
	char c=getchar();
	while('0'>c||c>'9')
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	x*=f;
}
void write(long long x)
{
	if(x>9)
		write(x/10);
	putchar(x%10+'0');
}
struct node
{
	int u;
	long long w;
	friend bool operator < (const node &a,const node &b)
	{
		return a.w>b.w;
	}
};
const long long basic=(1ll<<60);
int T;
int n,m,k;
int id[100005];
bool f[100005];
bool s_f[100005];
long long ans;
long long dis[100005];
vector<node> g[100005];
vector<node> f_g[100005];
void init()
{
	ans=basic;
	for(int i=1;i<=n+2;i++)
	{
		f_g[i].clear();
		g[i].clear();
		f[i]=0;
	}
}
void dij1()
{
	priority_queue<node> q;
	for(int i=1;i<=n;i++)
		dis[i]=basic;
	q.push((node){n+1,0});
	while(!q.empty())
	{
		node t=q.top();
		q.pop();
		if(t.w>dis[t.u])
			continue;
		if(t.w>ans)
			break;
		if(f[t.u]&&!s_f[t.u])
		{
			ans=min(ans,dis[t.u]);
			break;
		}
		for(int i=0;i<g[t.u].size();i++)
		{
			int v=g[t.u][i].u;
			if(dis[v]>dis[t.u]+g[t.u][i].w)
			{
				dis[v]=dis[t.u]+g[t.u][i].w;
				q.push((node){v,dis[v]});
			}	
		}
	}
}
void dij2()
{
	priority_queue<node> q;
	for(int i=1;i<=n;i++)
		dis[i]=basic;
	for(int i=0;i<f_g[n+1].size();i++)
	{
		dis[f_g[n+1][i].u]=0;
		q.push((node){f_g[n+1][i].u,0});
	}
	while(!q.empty())
	{
		node t=q.top();
		q.pop();
		if(t.w>dis[t.u])
			continue;
		if(t.w>ans)
			break;
		if(f[t.u]&&s_f[t.u])
		{ 
			ans=min(ans,dis[t.u]);
			break; 
		} 
		for(int i=0;i<g[t.u].size();i++)
		{
			int v=g[t.u][i].u;
			if(dis[v]>dis[t.u]+g[t.u][i].w)
			{
				dis[v]=dis[t.u]+g[t.u][i].w;
				q.push((node){v,dis[v]});
			}
		}
	}
}
void c_in()
{
	read(n);
	read(m);
	read(k);
	init();
	for(int i=1,u,v;i<=m;i++)
	{
		long long w;
		read(u);
		read(v);
		read(w);
		g[u].push_back((node){v,w});
	}
	for(int i=1;i<=k;i++)
	{
		read(id[i]);
		f[id[i]]=1;
	}
	for(int i=1;i<=17;i++)
	{
		g[n+1].clear();
		f_g[n+1].clear();
		for(int j=1;j<=k;j++)
		{
			if(id[j]&(1<<i))
			{
				s_f[id[j]]=1;
				g[n+1].push_back((node){id[j],0});
			}
			else
				f_g[n+1].push_back((node){id[j],0});	
		}
		dij1();
		dij2();
		for(int j=1;j<=k;j++)
			s_f[id[j]]=0;
	}
	write(ans);
	putchar('\n');
}
int main()
{
	read(T);
	for(int i=1;i<=T;i++)
		c_in();
	return 0;
}
posted @ 2019-12-17 09:49  loney_s  阅读(161)  评论(0)    收藏  举报