日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P1967,ssl2267-货车运输【树上倍增LCA,最小生成树变形kruskal】

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P1967,ssl2267-货车运输【树上倍增LCA,最小生成树变形kruskal】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:
https://www.luogu.org/problemnew/show/P1967


大意

一個無向圖,每個邊有個權值,若干個詢問,求兩個點之間的一條最短路是這條最短路上的最小權值最大。


解題思路

首先我們發現其實每兩個點之間留一條路徑就好了。
然后我們會發現如果x到y的路上最小權值最大是w,那么如果z有一條邊連向x,那么z到y的路上最小權值就有可能是w。
其實我們可以去掉一些邊只留需要的最大的邊就好了,這么一看其實就是留下最大生成樹。那么在樹上進行求LCA,然后在之前類似RMQ一樣預處理一下就可以求兩個點之間的最小權值了。


代碼

#include<cstdio> #include<queue> #include<algorithm> #include<cmath> using namespace std; queue<int> dl; struct line{int to,next,w,from; };//邊 struct pic{line a[100001];int ls[10001],tot;void addl(int x,int y,int w){a[++tot].to=y;a[tot].from=x;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot;} }p,tree;//圖 int t,n,m,q,x,y,z,s; int father[10001],f[10001][31],dis[10001][31],dep[10001]; int find(int x)//并查集-kruskal {return father[x]==x?x:father[x]=find(father[x]);} bool cmp(line x,line y)//排序-kruskal {return x.w>y.w;} void bfs(int open)//廣搜預處理-樹上倍增 {dl.push(open);dep[open]=1;while (dl.size()){int x=dl.front();dl.pop();for (int i=tree.ls[x];i;i=tree.a[i].next){int y=tree.a[i].to;if (dep[y]) continue;dl.push(y);f[y][0]=x;dep[y]=dep[x]+1;dis[y][0]=tree.a[i].w;}} } int LCA(int x,int y)//樹上倍增 {int ans=2147483647;if (dep[x]>dep[y]) swap(x,y);for (int i=t;i>=0;i--)if (dep[f[y][i]]>=dep[x])ans=min(ans,dis[y][i]),y=f[y][i];if (x==y) return ans;for (int i=t;i>=0;i--)if (f[y][i]!=f[x][i]) {ans=min(ans,min(dis[x][i],dis[y][i]));//統計x=f[x][i];y=f[y][i];}ans=min(ans,min(dis[x][0],dis[y][0]));return ans; } int main() {scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);p.addl(x,y,z);p.addl(y,x,z);}sort(p.a+1,p.a+1+p.tot,cmp);for (int i=1;i<=n;i++)father[i]=i;for (int i=1;i<=p.tot;i++){if (find(p.a[i].to)!=find(p.a[i].from)){s++;tree.addl(p.a[i].to,p.a[i].from,p.a[i].w);tree.addl(p.a[i].from,p.a[i].to,p.a[i].w);father[find(p.a[i].to)]=find(p.a[i].from);if (s==n) break;}}//kruskalt=(int)(log(n)/log(2))+1;for (int i=1;i<=n;i++)if (!dep[i]) {dis[i][0]=2147483647;bfs(i);//廣搜預處理}for (int j=1;j<=t;j++){for (int i=1;i<=n;i++){f[i][j]=f[f[i][j-1]][j-1];dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);}}//計算樹上倍增與統計路徑最小值的預處理scanf("%d",&q);for (int i=1;i<=q;i++){scanf("%d%d",&x,&y);if (find(x)!=find(y))printf("-1\n");//不連通elseprintf("%d\n",LCA(x,y));//輸出} }

總結

以上是生活随笔為你收集整理的P1967,ssl2267-货车运输【树上倍增LCA,最小生成树变形kruskal】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。