【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra
【题目】#6354. 「CodePlus 2018 4 月赛」最短路
【题意】给定n个点,m条带权有向边,任意两个点i和j还可以花费(i xor j)*C到达(C是给定的常数),求A到B的最短距离。\(n \leq 10^5,m \leq 5*10^5\)。
【算法】异或优化建图+Dijkstra
正常建边O(n2),与其考虑特殊边的处理不如考虑优化n2的建边方案。一个点x到另一个点y的代价是由每个改变的数位得到的,所以枚举所有点x的每个数位j,从x向\(x \ \ xor \ \ 2^j\)连边代价为\(2^j\)。
复杂度\(O((m+n \ \ log \ \ n) \ \ log \ \ n)\)。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
bool isdigit(char c){return c>='0'&&c<='9';}
int read(){
int s=0,t=1;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
do{s=s*10+c-'0';}while(isdigit(c=getchar()));
return s*t;
}
using namespace std;
const int maxn=100010,maxm=500010;
int tot,first[maxn],n,m,C,d[maxn];
struct edge{int v,w,from;}e[maxm+maxn*20];
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
struct cyc{
int d,id;
bool operator < (const cyc &a)const{
return d>a.d;
}
};
priority_queue<cyc>Q;
void dijkstra(int S){
memset(d,0x3f,sizeof(d));
d[S]=0;Q.push((cyc){0,S});
while(!Q.empty()){
cyc X=Q.top();Q.pop();
int D=X.d,x=X.id;
if(D!=d[x])continue;
for(int i=first[x];i;i=e[i].from)if(d[x]+e[i].w<d[e[i].v]){
d[e[i].v]=d[x]+e[i].w;
Q.push((cyc){d[e[i].v],e[i].v});
}
}
}
int main(){
n=read();m=read();C=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);
}
for(int i=0;i<=n;i++){//
for(int j=0;j<=18;j++)if((i^(1<<j))<=n){
insert(i,i^(1<<j),(1<<j)*C);
}
}
int A=read(),B=read();
dijkstra(A);
printf("%d",d[B]);
return 0;
}