这道题 首先不难看出要先求一个最大生成树,因为我们在尽量图联通的情况下,使两点之间有一条权值最大的边,所以Kru跑一遍最大生成树;
然后会有很显然的事情就是裸的生成树只能求总和,但我们需要知道树上有哪条边,所以在合并两个联通块时,将两个端点以及他们间的边加入另一个图中,那么显然新图中只包含最大生成树上的边,然后就是求两点之间的最长边,一个比较暴力的做法是floyed求任意两点间的最长边,但我们观察到点数<=10000,floyed显然不可取,那么正解是什么呢?
倍增Lca,我们不难发现,如果两个点联通的话,那么从两个点出发,必定会交于一点,显然这个点是他们的公共祖先,所以预处理每个点到他的祖先的最长边,询问时,再跑lca就可以啦
代码 1400ms//By AcerMo #include<cmath> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int M=100500; struct edge { int from,to,cost; bool friend operator < (edge a,edge b) { return a.cost<b.cost; } }now;//初始建图 priority_queue<edge>q; struct map { int to,cost; }_233;//新图 vector<map>v[M]; int n,m,que; int vis[M],deep[M],pt[M][21]; int fa[M],size[M],fatt[M][21]; int find(int x) { if (x!=fa[x]) return fa[x]=find(fa[x]); return x; } void unionn(int a,int b) { if (size[a]<=size[b]) size[b]+=size[a],fa[a]=b; else size[a]+=size[b],fa[b]=a; return ; }//加入了按秩合并以及路径压缩 void constt() { for (int i=0;i<=n;i++) size[i]=1,fa[i]=i,fatt[i][0]=i,pt[i][0]=M<<5; return ; }//初始化每个点的信息 void kru() { int cnt=1;constt(); while (q.size()&&cnt<n) { now=q.top();q.pop(); int r1=find(now.from); int r2=find(now.to); if (r1!=r2) { unionn(r1,r2),cnt++; _233.to=now.to;_233.cost=now.cost;v[now.from].push_back(_233); _233.to=now.from;_233.cost=now.cost;v[now.to].push_back(_233); }//注意加入新图的是原点而不是祖先 } return ; }//最大生成树及构建新图 void getlca(int x) { vis[x]=1; for (int i=0;i<v[x].size();i++) { int go=v[x][i].to; if (vis[go]) continue; deep[go]=deep[x]+1; fatt[go][0]=x; pt[go][0]=v[x][i].cost; getlca(go); } return ; }//构建lca祖先关系 void getminpath() { for (int i=1;i<=20;i++) for (int k=1;k<=n;k++) { fatt[k][i]=fatt[fatt[k][i-1]][i-1]; pt[k][i]=min(pt[k][i-1],pt[fatt[k][i-1]][i-1]); } return ; }//预处理每个点到祖先的距离 int lca(int x,int y) { if (find(x)!=find(y)) return -1; int ans=M<<5; if (deep[x]>deep[y]) swap(x,y); for (int i=20;i>=0;i--) if (deep[fatt[y][i]]>=deep[x]) ans=min(ans,pt[y][i]),y=fatt[y][i]; if (x==y) return ans; for (int i=20;i>=0;i--) if (fatt[x][i]!=fatt[y][i]) ans=min(ans,min(pt[x][i],pt[y][i])), x=fatt[x][i],y=fatt[y][i]; ans=min(ans,min(pt[x][0],pt[y][0])); return ans; }//lca求解 int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) scanf("%d%d%d",&now.from,&now.to,&now.cost),q.push(now); kru();scanf("%d",&que); for (int i=1;i<=n;i++) if (!vis[i]) getlca(i); getminpath(); while (que--) { int x,y; scanf("%d%d",&x,&y); int ans=lca(x,y); cout<<ans<<endl; } return 0; }