Solution [Code+#4]最短路
题目大意:图上任意两点(u,v)间有权值为((u;xor;v) imes c)的无向边,再添加给定的(m)条有向边之后,询问(s)到(t)的最短路
最短路
分析:首先给定的有向边我们肯定直接连上,剩下的无向边规模极大直接跑最短路会炸掉
我们考虑去除无用的边,如果当前点为(u),就将(u)与和它二进制表示只有一位不同的(v)连边。如果((u,v))直接的连边被去掉了,它可以通过图上路径表示出来,不会影响正确性
边的规模便可以降到(O(nlogn))
#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1e5 + 100;
inline int read(){
int x = 0;char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))x = x * 10 + c - '0',c = getchar();
return x;
}
struct edge{int v,d;};
vector<edge> G[maxn];
inline void addedge(int u,int v,int d){
G[u].push_back(edge{v,d});}
int vis[maxn],dis[maxn],n,m,c,s,t;
struct node{
int u,h;
bool operator < (const node &rhs)const{
return h > rhs.h;
}
};
priority_queue<node> Q;
inline void dijkstra(int s){
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;Q.push(node{s,0});
while(!Q.empty()){
int u = Q.top().u;Q.pop();
if(vis[u])continue;
vis[u] = 1;
for(auto e : G[u]){
if(dis[u] + e.d < dis[e.v]){
dis[e.v] = dis[u] + e.d;
Q.push(node{e.v,dis[e.v]});
}
}
for(int i = 20;i >= 0;i--)
if((u ^ (1 << i)) <= n && (dis[u] + (1 << i) * c) < dis[u ^ (1 << i)]){
dis[u ^ (1 << i)] = dis[u] + (1 << i) * c;
Q.push(node{u ^ (1 << i),dis[u ^ (1 << i)]});
}
}
}
int main(){
n = read(),m = read(),c = read();
for(int u,v,d,i = 1;i <= m;i++)
u = read(),v = read(),d = read(),addedge(u,v,d);
s = read(),t = read();
dijkstra(s);
printf("%d
",dis[t]);
return 0;
}