题目链接

题目大意:图上任意两点\(u,v\)间有权值为\((u\;xor\;v) \times 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\n",dis[t]);
    return 0;
}

相关文章:

  • 2021-05-17
  • 2021-06-24
  • 2021-05-31
  • 2021-06-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-18
猜你喜欢
  • 2021-06-20
  • 2022-01-10
  • 2021-06-01
  • 2021-11-12
  • 2021-11-10
  • 2022-12-23
相关资源
相似解决方案