因为要求最长集合线段中的最小值所以果断使用最大生成树,因为给定的是张图,无法确定唯一路径,而在树上就是了
再去求相当于两点分别为端点的链上最小值
以前写过树上路径,详情请点击(T1)
所以这时就成了一道板子题了
注意:这或许不仅仅只有一棵树,遍历找没有访问过的点重新当根即可。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } int f[10001],n,m; struct node{ int u,v,w,nex; }x[50001]; int head[10001],cnt; void add(int u,int v,int w) { x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++; } struct node1{ int a,b,c; }s[50001]; int sry; bool cmp(node1 x1,node1 x2) { return x1.c>x2.c; } int find(int x) { if(f[x]==x) return x; return f[x]=find(f[x]); } int fa[10001][21]; int minn[10001][21],deep[10001]; void dfs(int f,int fath) { fa[f][0]=fath; deep[f]=deep[fath]+1; for(int i=1;(1<<i)<=deep[f];i++) { fa[f][i]=fa[fa[f][i-1]][i-1]; minn[f][i]=min(minn[f][i-1],minn[fa[f][i-1]][i-1]); } for(int i=head[f];i!=-1;i=x[i].nex) { if(x[i].v==fath) continue; minn[x[i].v][0]=x[i].w; dfs(x[i].v,f); } } int q; int lca(int u,int v) { if(deep[u]==0||deep[v]==0) return -1; if(find(u)!=find(v)) return -1; int ans=2<<30-1; if(deep[u]<deep[v]) swap(u,v); for(int i=20;i>=0;i--) if(deep[u]-(1<<i)>=deep[v]) { ans=min(ans,minn[u][i]); u=fa[u][i]; } if(u==v) return ans; for(int i=20;i>=0;i--) { if(fa[u][i]==fa[v][i]) continue; ans=min(ans,minn[u][i]),u=fa[u][i]; ans=min(ans,minn[v][i]),v=fa[v][i]; } ans=min(ans,minn[u][0]),u=fa[u][0]; ans=min(ans,minn[v][0]),v=fa[v][0]; return ans; } int main() { memset(head,-1,sizeof(head)); n=read(),m=read(); for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) s[i].a=read(),s[i].b=read(),s[i].c=read(); sort(s+1,s+m+1,cmp); for(int i=1;i<=m;i++) { int t1=find(s[i].a),t2=find(s[i].b); if(t1!=t2) { f[t2]=t1; sry++; add(s[i].a,s[i].b,s[i].c),add(s[i].b,s[i].a,s[i].c); } } for(int i=1;i<=n;i++) { if(deep[i]==0) dfs(i,0); } q=read(); for(int i=1;i<=q;i++) { int u=read(),v=read(); printf("%d ",lca(u,v)); } }