bzoj3732 Network 最小生成树+LCA+树上倍增

xiaoxiao2021-02-28  198

这道题不就是Noip2013的t3吗…没想到bzoj换了个包装.noip2013货车运输是最大生成树,这里是最小生成树. 因为要是最大的边最小,则一定存在于最小生成树中.我们只需要跑一遍kruskal再树上倍增求LCA的同时求最大值即可.

注意:代码中Min其实求的是最大值,因为我直接从之前noip2013粘过来的,所以这里偷懒一下只改一下符号没改名称.

#include<stdio.h> #include<algorithm> const int maxn=100001; const int Uplimit=16; int aa,bb,tot,num,ans,h[maxn],fa[maxn],anc[maxn][Uplimit],vmin[maxn][Uplimit],n,m,dep[maxn],q; inline int Min(int x,int y){ return x>y?x:y;} struct optimus{ int x,y,z; }prime[maxn]; struct edge{ int nxt,v,w; }e[maxn*2]; inline void add(int u,int v,int w){ e[++num].v=v,e[num].w=w,e[num].nxt=h[u],h[u]=num; e[++num].v=u,e[num].w=w,e[num].nxt=h[v],h[v]=num; } inline bool cmp(optimus a,optimus b){return a.z<b.z;} inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ register int x=0; register char ch=nc(); while(ch<'0'||ch>'9')ch=nc(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=nc(); return x; } int I_Just_Wanna_Run(int x){return x==fa[x]?x:fa[x]=I_Just_Wanna_Run(fa[x]);} inline void kruskal(){ std::sort(prime+1,prime+m+1,cmp); for(register int i=1;i<=n;i++) fa[i]=i; for(register int i=1;i<=m;i++){ aa=I_Just_Wanna_Run(prime[i].x),bb=I_Just_Wanna_Run(prime[i].y); if(aa!=bb){ ++tot; fa[aa]=bb; add(prime[i].x,prime[i].y,prime[i].z); if(tot==n-1) break; } } } void dfs(int u,int father,int value){ dep[u]=dep[father]+1; anc[u][0]=father,vmin[u][0]=value; for(int p=1;p<Uplimit;p++) anc[u][p]=anc[anc[u][p-1]][p-1],vmin[u][p]=Min(vmin[u][p-1],vmin[anc[u][p-1]][p-1]); for(int i=h[u];i;i=e[i].nxt){ int v=e[i].v; if(v==father) continue; dfs(v,u,e[i].w); } } int query(int u,int v){ ans=0; if(dep[u]<dep[v]) std::swap(u,v); int D_depth=dep[u]-dep[v]; for(int p=0;D_depth;D_depth>>=1,p++) if(D_depth&1)ans=Min(ans,vmin[u][p]),u=anc[u][p]; if(u==v) return ans; for(int p=Uplimit-1;p>=0;p--) if(anc[u][p]!=anc[v][p]) ans=Min(ans,Min(vmin[u][p],vmin[v][p])),u=anc[u][p],v=anc[v][p]; return ans=Min(ans,Min(vmin[u][0],vmin[v][0])); } int main(){ n=read(),m=read();q=read(); for(register int i=1;i<=m;i++) prime[i].x=read(),prime[i].y=read(),prime[i].z=read(); kruskal(); for(register int i=1;i<=n;i++) if(!dep[i]) dfs(i,i,0); while(q--){ int x=read(),y=read(); if(I_Just_Wanna_Run(x)!=I_Just_Wanna_Run(y)) printf("-1\n"); else printf("%d\n",query(x,y)); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-41112.html

最新回复(0)