习题:旅行者(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;
}

浙公网安备 33010602011771号