YbtOJ#631-次短路径【左偏树,最短路】

1|0正题

题目链接:https://www.ybtoj.com.cn/contest/114/problem/1


1|1题目大意

给出n个点m条边的一张无向图,对于每个点i求不经过i1的最短路的第一条边的情况下i1的最短路

数据保证这条边唯一

n[1,105],m[1,2×105],c[1,103]


1|2解题思路

因为保证的那个东西,所以图的最短路树真的是一棵树了,所以先跑出最短路树考虑在最短路树上面搞。

然后题目限制了我们不能从树上的祖先那条边过来,这样就分为了两种情况。一种是从该点的子树外面连过来的边,另一种是从子树中走上来的边。第二种很麻烦,因为子树的最短路是用该节点的最短路扩展的,所以不能直接使用。

考虑一条非树边(x,y),这条边会扩展一条disy+wx的路径。(disx表示1x的最短路)。

并且这条边可以使用到LCA(x,y)处,此时x的祖先们都不包含y在子树内,可以直接用y的子树扩展。

所以可以维护一个左偏树,每次合并两个儿子的信息,如果堆顶的边需要被删除就删除。需要写一个lazy标记来修改整棵树

时间复杂度O(nlogn)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define mp(x,y) make_pair(x,y) using namespace std; const int N=4e5+10; struct point{ int val,x,y; point(int v=0,int xx=0,int yy=0) {val=v;x=xx;y=yy;return;} }; bool operator<(point x,point y) {return x.val<y.val;} struct Heap{ point val[N]; int t[N][2],lazy[N],dis[N]; void Downdata(int x){ if(!lazy[x])return; int ls=t[x][0],rs=t[x][1]; lazy[ls]+=lazy[x];lazy[rs]+=lazy[x]; val[ls].val+=lazy[x];val[rs].val+=lazy[x]; lazy[x]=0;return; } int Merge(int x,int y){ Downdata(x);Downdata(y); if(!x||!y)return x+y; if(val[y]<val[x])swap(x,y); int &ls=t[x][0],&rs=t[x][1]; rs=Merge(rs,y); if(dis[rs]>dis[ls])swap(ls,rs); dis[x]=dis[rs]+1;return x; } int Del(int x){ int &ls=t[x][0],&rs=t[x][1];val[x]=0; return Merge(ls,rs); } }T; struct node{ int to,next,w; }a[N]; int n,m,tot,cnt,num,ls[N],f[N]; int rfn[N],p[N],ans[N]; bool v[N];vector<int> G[N]; priority_queue<pair<int,int> >q; void addl(int x,int y,int w){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;a[tot].w=w; return; } void dij(){ memset(f,0x3f,sizeof(f)); q.push(mp(0,1));f[1]=0; while(!q.empty()){ int x=q.top().second;q.pop(); if(v[x])continue;v[x]=1; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(f[x]+a[i].w<f[y]){ f[y]=f[x]+a[i].w; q.push(mp(-f[y],y)); } } } return; } void dfs(int x){ rfn[x]=++cnt; for(int i=0;i<G[x].size();i++){ int y=G[x][i];dfs(y); T.val[p[y]].val+=f[y]-f[x]; T.lazy[p[y]]+=f[y]-f[x]; p[x]=T.Merge(p[x],p[y]); } for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(f[x]+a[i].w==f[y])continue; if(f[y]+a[i].w==f[x])continue; T.val[++num]=point(f[y]+a[i].w,x,y); p[x]=T.Merge(p[x],num); } while(1){ if(!p[x]){ans[x]=-1;break;} point w=T.val[p[x]]; if(rfn[w.y]>=rfn[x]) {p[x]=T.Del(p[x]);continue;} ans[x]=w.val;break; } return; } int main() { freopen("pal.in","r",stdin); freopen("pal.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y,w; scanf("%d%d%d",&x,&y,&w); addl(x,y,w);addl(y,x,w); } dij(); for(int x=1;x<=n;x++) for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(f[x]+a[i].w==f[y]) G[x].push_back(y); } dfs(1); for(int i=2;i<=n;i++) if(!ans[i])puts("-1"); else printf("%d\n",ans[i]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14403830.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(34)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示