NOIP2013 提高組D1T3 貨車運輸
題目連結:ofollow,noindex" target="_blank">https://www.luogu.org/problemnew/show/P1967
思路:
先跑一遍,但是是最大生成樹,然後倍增求,向公共祖先靠近時更新最小值即可。程式碼實現難度較大。
程式碼:
#include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <algorithm> static const int MAXN=10050; static const int MAXM=50050; static const int INF=1<<30; struct node1 { int u,v,w; }a[MAXM]; struct node2 { int to,val,nextt; }edge[MAXM<<1]; int n,m,q,x,y,t,num,Min,cnt,dep[MAXN],head[MAXN],fa[MAXN],f[MAXN][25],g[MAXN][50]; bool vis[MAXN]; inline int read() { int x=0;bool sign=false; char alpha=0; while(!isdigit(alpha)) sign|=alpha=='-',alpha=getchar(); while(isdigit(alpha)) x=(x<<1)+(x<<3)+(alpha^48),alpha=getchar(); return sign?-x:x; } inline bool cmp(node1 a,node1 b){return a.w>b.w;} inline int get_min(int a,int b){return a<b?a:b;} inline void addedge(int u,int v,int w) { edge[++num].to=v; edge[num].val=w; edge[num].nextt=head[u]; head[u]=num; } inline int find(int x) { int t=x,pre; while(t!=fa[t]) t=fa[t]; while(x!=t) { pre=fa[x]; fa[x]=t; x=pre; } return t; } inline void kruscal() { std::sort(a+1,a+m+1,cmp); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int fx=find(a[i].u),fy=find(a[i].v); if(fx==fy) continue; fa[fy]=fx; addedge(fx,fy,a[i].w); addedge(fy,fx,a[i].w); if(++cnt==n-1) break; } } void dfs(int x) { vis[x]=true; for(int i=1;(1<<i)<=dep[x];i++) { f[x][i]=f[f[x][i-1]][i-1]; g[x][i]=get_min(g[x][i-1],g[f[x][i-1]][i-1]); } for(int i=head[x];i;i=edge[i].nextt) { int to=edge[i].to; if(vis[to]) continue; dep[to]=dep[x]+1; f[to][0]=x; g[to][0]=edge[i].val; dfs(to); } } inline int lca(int x,int y) { if(dep[x]>dep[y]) std::swap(x,y); int dif=dep[y]-dep[x]; for(int i=0;i<=20;i++) if((1<<i)&dif) y=f[y][i]; for(int i=20;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return x==y?x:f[x][0]; } inline int solve(int x,int y) { Min=INF; int dif=dep[x]-dep[y]; for(int i=0;i<=20;i++) { if((1<<i)&dif) { Min=get_min(Min,g[x][i]); x=f[x][i]; } } return Min; } int main() { n=read();m=read(); for(int i=1;i<=m;i++) a[i].u=read(),a[i].v=read(),a[i].w=read(); kruscal(); memset(g,127/2,sizeof(g)); for(int i=1;i<=n;i++) if(!vis[i]) dfs(i); q=read(); for(int i=1;i<=q;i++) { x=read();y=read(); t=lca(x,y); find(x)==find(y)?printf("%d\n",get_min(solve(x,t),solve(y,t))):printf("-1\n"); } return 0; }