• 【GXOI/GZOI2019】旅行者


    题面

     https://www.luogu.org/problem/P5304

    题解

    可能是“最短路”标签下最难的一道题了吧,还是要补说几句的。

    对于任意一对点,他们的最短路有两种情况:

    • 一条边直达
    • 经过别的点中转

    第一种情况直接特判掉。

    对于第二种情况

    跑多源$dijkstra$,正跑一次,再反跑一次。每次记录这个点的最短路是由哪个点过来的。

    本来是这样想的,第二次跑时,记录每个点正跑跑到的最近的点和反跑跑到的最近点,但是如果两个相等(比如存在环),就假了。

    为了让这个过程更严谨些,我们在松弛操作的过程中,检查$(u,v)$ $from[u][1]$是否等于$from[v][0]$,如果不等于,可以用其更新答案。

    莫名想到后缀自动机求$[l,r]$最长相同的后缀时用$set$进行启发式合并(我好像已经忘了怎么求),感觉有异曲同工之妙啊。

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ri register int
    #define N 100500
    #define M 1000500
    #define LL long long
    #define INF 1000000007LL
    using namespace std;
    
    struct node {
      int v; LL dis;
      bool operator < (const node &rhs) const {
        return dis>rhs.dis;
      }
    };
    
    int n,m,k;
    vector<int> id[N];
    int to[M],len[M],cc;
    int a[N];
    priority_queue<node> pq;
    
    LL dis[N][2],ans;
    int fro[N][2];
    bool imp[N],vis[N];
    
    void add_egde(int a,int b,int c) {
      id[a].push_back(++cc); to[cc]=b; len[cc]=c;
      id[b].push_back(++cc); to[cc]=a; len[cc]=c;
    }
    
    void dij(int opt) {
      for (ri i=1;i<=n;i++) dis[i][opt]=INF*INF,vis[i]=0;
      while (!pq.empty()) pq.pop();
      for (ri i=1;i<=k;i++) {
        dis[a[i]][opt]=0;
        fro[a[i]][opt]=a[i];
        pq.push((node){a[i],dis[a[i]][opt]});
      }
      while (!pq.empty()) {
        int x=pq.top().v; pq.pop();
        if (vis[x]) continue;
        vis[x]=1;
        for (ri i=0,ls=id[x].size();i<ls;i++) {
          int e=id[x][i];
          if (e%2!=opt) continue;
          if (dis[x][opt]+len[e]<dis[to[e]][opt]) {
            dis[to[e]][opt]=dis[x][opt]+len[e];
            fro[to[e]][opt]=fro[x][opt];
            pq.push((node){to[e],dis[to[e]][opt]});
          }
          if (opt) {
            if (dis[x][opt]+len[e]+dis[to[e]][opt^1]<ans && fro[x][opt]!=fro[to[e]][opt^1]) ans=dis[x][opt]+len[e]+dis[to[e]][opt^1];
          }
        }
      }
    }
    
    int main(){
      int T,z,y,x;
      scanf("%d",&T);
      while (T--) {
        scanf("%d %d %d",&n,&m,&k);
        for (ri i=1;i<=n;i++) id[i].clear();
        cc=-1;
        for (ri i=1;i<=m;i++) {
          scanf("%d %d %d",&z,&y,&x);
          if (z!=y) add_egde(z,y,x);
        }
        ans=INF*INF;
        memset(imp,0,sizeof(imp));
        for (ri i=1;i<=k;i++) {
          scanf("%d",&a[i]);
          imp[a[i]]=1;
          for (ri j=0,ls=id[a[i]].size();j<ls;j++) {
            int e=id[a[i]][j];
            if (imp[to[e]] && len[e]<ans) ans=len[e];
          }
        }
        dij(0); dij(1);
        for (ri i=1;i<=n;i++) if (fro[i][0]!=fro[i][1] && dis[i][0]+dis[i][1]<ans) ans=dis[i][0]+dis[i][1];
        printf("%lld
    ",ans);
      }
    }
  • 相关阅读:
    WPF之TextBox和PasswordBox水印效果
    C#中<%%><%#%><%=%> 分别代表的含义
    jQuery AJAX 方法
    .net中在读取控件的class或ID不同方式的不同意义- jquery选择器
    通过xml操作网页
    jquery 取元素
    fadeIn fadeOut
    怎么取jquery中的数据
    小知识(1)
    原生js方法document.getElementsByClassName在ie8及其以下的兼容性问题
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11278508.html
Copyright © 2020-2023  润新知