洛谷 P1967 货车运输
https://www.luogu.org/problem/show?pid=1967
思路:
先生成一颗最大生成树,然后走LCA,这过程一直取min。
在这过程中要重新构图(建一颗树)记录其第2^i的父节点,和这段路径中的最小边。
当然最重要的是LCA,写的不熟练。
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<cmath> using namespace std; const int N=1009; long long n,m,q; struct node{ long long x,y,z; }E[50*N]; long long h[N*10],nex[50*N],to[50*N],cnt,w[50*N]; long long f[N*10]; long long deep[N*10],f1[N*10][50],f2[N*10][50],dad[N*10]; bool cmp(node a,node b) {return a.z>b.z;}; long long find(long long x) { while(x!=f[x]) x=f[x]=f[f[x]]; return x; } void build(int x) { for(int i=h[x];i;i=nex[i]) { if(to[i]==dad[x]) continue; dad[to[i]]=x; f1[to[i]][0]=x; f2[to[i]][0]=w[i]; deep[to[i]]=deep[x]+1; build(to[i]); } } long long work(long long s,long long e) { long long ans=2100000000; if(deep[s]<deep[e]) { long long c=e; e=s; s=c; } for (long long i=16;i>=0;--i) if (f1[s][i]!=0&&deep[f1[s][i]]>=deep[e]) { ans=min(ans,f2[s][i]); s=f1[s][i]; } if (s==e) return ans; for (long long i=16;i>=0;--i) { if (f1[s][i]!=f1[e][i]) { ans=min(min(f2[s][i],f2[e][i]),ans); s=f1[s][i]; e=f1[e][i]; } } ans=min(min(f2[s][0],f2[e][0]),ans); return ans; } void Add(int f,int too,int ww) { to[++cnt]=too,nex[cnt]=h[f];h[f]=cnt;w[cnt]=ww; to[++cnt]=f,nex[cnt]=h[too],h[too]=cnt;w[cnt]=ww; } int main()//最大生成树 { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) f[i]=i; for(int i=1,z,x,y;i<=m;i++) { scanf("%lld%lld%lld",&E[i].x,&E[i].y,&E[i].z); } sort(E+1,E+1+m,cmp); for(int i=1;i<=m;i++) { int f1=find(E[i].x),f2=find(E[i].y); if(f1==f2) continue; f[f2]=f1; Add(E[i].x,E[i].y,E[i].z); } for(int i=1;i<=n;i++) if(f[i]==i) { dad[i]=i; deep[i]=1; build(i); } for(int i=1;i<=16;i++) for(int j=1;j<=n;j++) { f1[j][i]=f1[f1[j][i-1]][i-1]; f2[j][i]=min(f2[j][i-1],f2[f1[j][i-1]][i-1]); } long long q,x,y; cin>>q; for(int i=1;i<=q;i++) { scanf("%lld%lld",&x,&y); if(find(x)!=find(y)) printf("-1\n"); else printf("%lld\n",work(x,y)); } return 0; }