• [usaco jan 09] 安全路径 travel [最短路径树]


    题面:

    传送门

    思路:

    既然最后一条边不能走,那么就一定是换了一条路,一条不经过这最后一条边的路

    如果想要这条路最短,那么其在路上一定尽可能多地走了最短路径

    因此,我们对这张图跑一遍从1开始的单源最短路,并建立出最短路径树

    那么新的路径(1->u)一定是这样构成的:(1->v)+edge(v,w)+(w->u),其中w是u在最短路径树上的后代

    那么,我们对于每一条非树边(u,v),其树上路径上所有点(除了lca)的答案,都可以被dis[u]+dis[v]+w(u,v)-dis[路径上的点]来更新

    然而,直接每一次这样更新,时间效率肯定不行

    对上述的结论进一步分析,可以发现,实际上dis[u]+dis[v]+w(u,v)对于每条非树边(u,v)固定

    因此可以把dis[u]+dis[v]+w(u,v)排序,对于每一条非树边依次操作,并且使用并查集来跳过已经更新过得边

    总时间复杂度:dij O(nlogn),排序 O(mlogm) 更新答案 O(n)

    Code:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<vector>
     7 using namespace std;
     8 struct edge{
     9     int to,w,next;
    10 }e[400100];
    11 struct new_edge{
    12     int from,to,w;
    13 }x[400100];
    14 struct node{
    15     int num,fa;
    16     vector<int>son;
    17 }a[100100];
    18 int n,m,first[100100],pre[100100],dis[100100],f[100100],ans[100100];
    19 bool vis[100100];
    20 void spfa(){
    21     int i,u,v,w;
    22     queue<int>q;memset(dis,127,sizeof(dis));
    23     q.push(1);pre[1]=1;dis[1]=0;
    24     while(!q.empty()){
    25         u=q.front();q.pop();vis[u]=0;
    26         for(i=first[u];~i;i=e[i].next){
    27             v=e[i].to;w=e[i].w;
    28             if(dis[v]>dis[u]+w){
    29                 dis[v]=dis[u]+w;pre[v]=u;
    30                 if(!vis[v]){
    31                     vis[v]=1;q.push(v);
    32                 }
    33             }
    34         }
    35     }
    36 }
    37 bool cmp(new_edge l,new_edge r){
    38     return l.w<r.w;
    39 }
    40 int find(int x){
    41     return ((f[x]==x)?x:f[x]=find(f[x]));
    42 }
    43 int aa[200100],bb[200100],cc[200100];
    44 int main(){
    45     freopen("travel.in","r",stdin);
    46     freopen("travel.out","w",stdout);
    47     memset(first,-1,sizeof(first));
    48     memset(ans,-1,sizeof(ans));
    49     int i,j,t1,t2,t3,l,r;
    50     scanf("%d%d",&n,&m);
    51     for(i=1;i<=m;i++){
    52         scanf("%d%d%d",&t1,&t2,&t3);
    53         e[i*2-1].to=t2;e[i*2-1].next=first[t1];e[i*2-1].w=t3;first[t1]=i*2-1;
    54         e[i*2].to=t1;e[i*2].next=first[t2];e[i*2].w=t3;first[t2]=i*2;
    55         aa[i]=t1;bb[i]=t2;cc[i]=t3;
    56     }
    57     spfa();
    58 //    for(i=1;i<=n;i++) cout<<pre[i]<<ends<<dis[i]<<endl;
    59 //    for(i=1;i<=m;i++) cout<<aa[i]<<ends<<bb[i]<<ends<<cc[i]<<endl;
    60 //    cout<<"end of spfa"<<endl;
    61     for(i=1;i<=n;i++){
    62         a[i].num=i;f[i]=i;
    63         a[i].fa=pre[i];
    64         if(i!=1) a[pre[i]].son.push_back(i);
    65     }
    66     int cnt=0;
    67     for(i=1;i<=m;i++){
    68         if(pre[aa[i]]==bb[i]||pre[bb[i]]==aa[i]) continue;
    69 //        cout<<aa[i]<<ends<<bb[i]<<ends<<cc[i]<<endl;
    70         x[++cnt].from=aa[i];x[cnt].to=bb[i];x[cnt].w=dis[aa[i]]+dis[bb[i]]+cc[i];
    71     }
    72 //    cout<<"end2"<<endl;
    73     sort(x+1,x+cnt+1,cmp);
    74     for(i=1;i<=cnt;i++){
    75         l=find(x[i].from);r=find(x[i].to);
    76         while(l!=r){
    77             if(dis[l]<dis[r]) swap(l,r);
    78             ans[l]=x[i].w-dis[l];
    79             f[l]=pre[l];l=find(l);
    80         }
    81     }
    82     for(i=2;i<=n;i++) printf("%d
    ",ans[i]);
    83 }
  • 相关阅读:
    Python文件操作
    Python操作MySQL数据库
    Can't connect to MySQL server (10065)
    CentOS安装Navicat
    机器学习中Batch Size、Iteration和Epoch的概念
    Python禁用GC优化性能
    TensorFlow迭代速度变慢的问题
    Linear SVM和LR的区别和联系
    拉格朗日乘子法和KKT条件
    Python机器学习(1):KMeans聚类
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8457131.html
Copyright © 2020-2023  润新知