[CP1804]最短路
题目大意:
一个$n(n\le10^5)$个点的图,给定一个常数$c$,每对点$i,j$之间有权值为$(i\oplus j)\times c$的边。另有$m(m\le5\times10^5)$条指定权值的单向边,求指定点对间的最短路。
思路:
显然当异或值二进制下只有一位$1$时,这条边才是有效的,否则一定可以经过若干个只有一位$1$的边得到更优的解。只考虑$m$条给定边,同时对于每个点枚举异或值,直接跑Dijkstra即可。
1 #include<cstdio> 2 #include<cctype> 3 #include<climits> 4 #include<functional> 5 #include<forward_list> 6 #include<ext/pb_ds/priority_queue.hpp> 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 const int N=1e5+1; 15 typedef std::pair<int,int> Edge; 16 std::forward_list<Edge> e[N]; 17 inline void add_edge(const int &u,const int &v,const int &w) { 18 e[u].push_front((Edge){v,w}); 19 } 20 int n,m,c,dis[N]; 21 typedef std::pair<int,int> Vertex; 22 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex>> q; 23 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex>>::point_iterator p[N]; 24 inline void dijkstra(const int &s) { 25 for(register int i=1;i<=n;i++) { 26 p[i]=q.push((Vertex){dis[i]=i==s?0:INT_MAX,i}); 27 } 28 while(!q.empty()) { 29 const int &x=q.top().second; 30 for(register Edge i:e[x]) { 31 const int &y=i.first,&w=i.second; 32 if(dis[x]+w<dis[y]) { 33 q.modify(p[y],(Vertex){dis[y]=dis[x]+w,y}); 34 } 35 } 36 for(register int i=1;i<=n;i<<=1) { 37 if((x^i)>n) continue; 38 if(dis[x]+i*c<dis[x^i]) { 39 q.modify(p[x^i],(Vertex){dis[x^i]=dis[x]+i*c,x^i}); 40 } 41 } 42 q.pop(); 43 } 44 } 45 int main() { 46 n=getint(),m=getint(),c=getint(); 47 for(register int i=0;i<m;i++) { 48 const int u=getint(),v=getint(),w=getint(); 49 add_edge(u,v,w); 50 } 51 dijkstra(getint()); 52 printf("%d\n",dis[getint()]); 53 return 0; 54 }