【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;
}
posted @ 2018-05-24 14:31  ONION_CYC  阅读(...)  评论(...编辑  收藏