[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 } 

 

posted @ 2018-04-02 20:41  skylee03  阅读(128)  评论(0编辑  收藏  举报