题面:
思路:
既然最后一条边不能走,那么就一定是换了一条路,一条不经过这最后一条边的路
如果想要这条路最短,那么其在路上一定尽可能多地走了最短路径
因此,我们对这张图跑一遍从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\n",ans[i]); 83 }