传送门(最短路树+可并堆)
生活随笔
收集整理的這篇文章主要介紹了
传送门(最短路树+可并堆)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
有一張n個點m條邊的無向圖,求刪去任意一條邊后,從S到T的最短距離的最大值
n, m ≤ 2×1052 \times 10^52×105
Solution
這道題是[USACO09JAN]Safe Travel的變形,然后這是題解
Safe Travel這道題的普遍做法是并查集或樹剖,但學長的PDF里提到的是題解講的可并堆做法,所以我就沒采用前兩種
然后講回傳送門這題,
首先考慮怎么求刪掉一條邊后相鄰兩個點到 T 的最短距離。建出最短路樹,如果刪掉的不是連向父親的邊,則最短路不變,否則就和Safe Travel一樣了
那么怎么求出最終答案呢?可以在圖上DP一下
對每個點 u,記 d(u) 表示 u 到 T 的最短路,e(u) 表示刪掉它和最短路樹上父親的邊后的最短路。令 dp(u) 表示 S = u 時的答案。每次找到 dp 值最小的點來更新其它的點的 dp 值即可。用 u 更新 v 時的轉移為 dp(v) =min { max(dp(u) + w(u, v), u == parent v?e(v) : d(v)) }。
Code
//一定不能把S,T反過來,不然就全WA了 #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; typedef long long ll; typedef pair<ll,int> pr; const int inf=0x7fffffff; const int N=2e5+5; const int M=2e5+5; struct Edge{int v,w,nxt,tr; }edge[M<<1]; int head[N],cnt,vis[N],pre[N];ll dis[N]; priority_queue<pr,vector<pr> ,greater<pr> > q; int siz[N],dfn[N],ind,parent[N];ll e[N],dp[N]; struct Node{int to,ls,rs,fa,dist;ll val; }t[M*20]; int tot,rt[N]; int n,m; void add_edge(int u,int v,int w){edge[++cnt].v=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt; } void dijskra(int s){for(int i=1;i<=n;i++) dis[i]=inf;memset(vis,0,sizeof(vis));dis[s]=0;q.push(make_pair(0,s));while(!q.empty()){pr tmp=q.top();q.pop();int u=tmp.second;if(vis[u]) continue;vis[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v,w=edge[i].w;if(dis[v]>dis[u]+1ll*w){dis[v]=dis[u]+1ll*w;pre[v]=i;q.push(pr(dis[v],v));}}} } void build(){//建最短路樹 for(int i=1;i<=n;i++)if(pre[i]) edge[pre[i]].tr=1; } int merge(int a,int b){if(!a||!b) return a+b;if(t[a].val>t[b].val) swap(a,b);t[a].rs=merge(t[a].rs,b);t[t[a].rs].fa=a;if(t[t[a].ls].dist<t[t[a].rs].dist) swap(t[a].ls,t[a].rs);t[a].dist=t[t[a].rs].dist+1;return a; } int pop(int a){return merge(t[a].ls,t[a].rs); } bool check(int u,int v){return dfn[v]>=dfn[u]&&dfn[v]<=dfn[u]+siz[u]-1; } void dfs(int u,int fa){dfn[u]=++ind;siz[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||!edge[i].tr) continue;parent[v]=u;dfs(v,u);rt[u]=merge(rt[u],rt[v]);siz[u]+=siz[v];}for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||edge[i].tr) continue;//(u,fa)也是樹邊,不考慮 t[++tot]=(Node){v,0,0,tot,0,dis[u]+dis[v]+edge[i].w};rt[u]=merge(rt[u],tot); }while(check(u,t[rt[u]].to)) rt[u]=pop(rt[u]);e[u]=rt[u]?t[rt[u]].val-dis[u]:inf; } void get_ans(int s){for(int i=1;i<=n;i++) dp[i]=inf;memset(vis,0,sizeof(vis));dp[s]=0;q.push(make_pair(0,s));while(!q.empty()){pr tmp=q.top();q.pop();int u=tmp.second;if(vis[u]) continue;vis[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v,w=edge[i].w;int t=max(dp[u]+w,parent[v]==u?e[v]:dis[v]);if(dp[v]>t){dp[v]=t;q.push(pr(dp[v],v));}}} } int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);add_edge(u,v,w);add_edge(v,u,w);}dijskra(n);build();tot=n;dfs(n,0);get_ans(n);if(dp[1]==inf) printf("%d\n",-1); else printf("%lld\n",dp[1]);return 0; }總結
以上是生活随笔為你收集整理的传送门(最短路树+可并堆)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 知网 CNKI 云版学术成果库发布,面向
- 下一篇: 郭明錤:苹果可能会在2025年重新设计M