#include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; const int N=1e4+5; const int INF=0x3f3f3f3f; struct Edge{ int u,v,w,next; bool operator<(const Edge &rhs)const{ return w>rhs.w; } }o[N*5],edge[N<<1]; int fa[N][20],fat[N],head[N],tot,p[N][14]; void add(int u,int v,int w){ edge[tot].w=w; edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } int find(int x){ if(x==fat[x])return x; return fat[x]=find(fat[x]); } int d[N]; void dfs(int u,int f){ d[u]=d[f]+1; fa[u][0]=f; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v; if(v==f)continue; dfs(v,u); p[v][0]=edge[i].w; } } int lca(int u,int v){ int ans=INF; if(d[u]<d[v])swap(u,v); for(int t=d[u]-d[v],i=0;t;t>>=1,++i) if(t&1)ans=min(p[u][i],ans),u=fa[u][i]; if(u==v)return ans; for(int i=16;i>=0;--i){ if(fa[u][i]!=-1&&fa[u][i]!=fa[v][i]){ ans=min(ans,p[u][i]); ans=min(ans,p[v][i]); u=fa[u][i],v=fa[v][i]; } } ans=min(ans,p[u][0]); ans=min(ans,p[v][0]); return ans; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;++i){ scanf("%d%d%d",&o[i].u,&o[i].v,&o[i].w); } sort(o+1,o+1+m); for(int i=1;i<=n;++i)fat[i]=i,head[i]=-1; int cnt=0; for(int i=1;i<=m;++i){ int x=find(o[i].u),y=find(o[i].v); if(x!=y){ fat[y]=x; ++cnt; add(o[i].u,o[i].v,o[i].w); add(o[i].v,o[i].u,o[i].w); if(cnt>=n-1)break; } } memset(p,INF,sizeof(p)); memset(fa,-1,sizeof(fa)); for(int i=1;i<=n;++i){ if(fat[i]==i){ dfs(i,0); fa[i][0]=-1; } } for(int j=1;(1<<j)<=n;++j){ for(int i=1;i<=n;++i){ if(fa[i][j-1]!=-1) { fa[i][j]=fa[fa[i][j-1]][j-1]; p[i][j]=min(p[i][j-1],p[fa[i][j-1]][j-1]); } } } int q; scanf("%d",&q); while(q--){ int u,v; scanf("%d%d",&u,&v); if(find(u)!=find(v)){ printf("-1\n"); continue; } printf("%d\n",lca(u,v)); } return 0; }
分析:
看这个就好http://hzwer.com/1344.html 仰慕黄学长
然后刚开始我没想写倍增,想写树剖的,后来一看,树剖勉强应该多一个log,而且代码长
所以倍增大法好