1. 程式人生 > >luogu P1396 營救

luogu P1396 營救

繼續 離線 eof fin www turn pid class code

原題鏈接:https://www.luogu.org/problem/show?pid=1396

剛一看到這個題,馬上就想起來前幾天剛做的貨車運輸,於是迅速地敲了個最小生成樹+lca求路徑上最長邊,寫完後一看標簽和難度,咦,為什麽沒有lca的標簽啊,為什麽這個題的難度只有普及/提高減啊,這個不是和貨車運輸差不多的嗎。。。

於是愉快的交上去A掉了之後,仔細想了想新的做法,又想出兩種做法:

1.倍增lca+最小生成樹:

基本上同貨車運輸:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace
std; void read(int &y) { y=0;char x=getchar(); while(x<0||x>9) x=getchar(); while(x>=0&&x<=9) { y=y*10+x-0; x=getchar(); } } struct edge { int u,v,w; }e[50005]; bool cmp(edge x,edge y) { return x.w<y.w; } int fa[10005][25],maxw[10005
][25]; int f[10005],head[20005],nxt[20005],to[20005],d[20005],dep[10005]; int n,m,s,t,cnt; int find(int x) { if(x==f[x]) return x; return f[x]=find(f[x]); } void add(int u,int v,int w) { to[cnt]=v; d[cnt]=w; nxt[cnt]=head[u]; head[u]=cnt++; } void dfs(int x,int y) { for(int i=head[x];i!=-1
;i=nxt[i]) { if(i!=y) { dep[to[i]]=dep[x]+1; fa[to[i]][0]=x; maxw[to[i]][0]=d[i]; dfs(to[i],i^1); } } } int lca(int x,int y) { if(dep[x]>dep[y]) { int tmp=x; x=y; y=tmp; } int ans=-1; for(int i=15;i>=0;i--) { if(dep[fa[y][i]]>=dep[x]) { ans=max(ans,maxw[y][i]); y=fa[y][i]; } } if(x==y) return ans; for(int i=15;i>=0;i--) { if(fa[x][i]!=fa[y][i]) { ans=max(ans,max(maxw[x][i],maxw[y][i])); x=fa[x][i]; y=fa[y][i]; } } return ans; } int main() { read(n);read(m);read(s);read(t); for(int i=0;i<m;i++) { read(e[i].u);read(e[i].v);read(e[i].w); } sort(e,e+m,cmp); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) f[i]=i; for(int i=0;i<m;i++) { if(find(e[i].u)!=find(e[i].v)) { add(e[i].u,e[i].v,e[i].w); add(e[i].v,e[i].u,e[i].w); f[find(e[i].u)]=find(e[i].v); } } dep[1]=1,dfs(1,-1); for(int j=1;j<=15;j++) { for(int i=1;i<=n;i++) { fa[i][j]=fa[fa[i][j-1]][j-1]; maxw[i][j]=max(maxw[i][j-1],maxw[fa[i][j-1]][j-1]); } } printf("%d",lca(s,t)); return 0; }

2.最小生成樹+暴力公共祖先:

此題只有一組數據,所以我們可以使用離線算法,首先求出圖的最小生成樹,然後由s節點暴力向上找父親節點,一路標記,到達根節點後停止。在由t節點向上暴力找父親節點,到達有標記的點之後停止。

然後兩點分別再向上到公共祖先,更新最大值,輸出即可。

3.最小生成樹+巧妙利用並查集性質:

繼續使用離線算法,然後使用克魯斯卡爾算法求最小生成樹,當s與t在一個集合中時,s到t的路徑就確定了,最長的邊就是當前要處理的邊,輸出即可。

luogu P1396 營救