noip2013day1t3货车运输(瓶颈路,树上倍增)
https://www.luogu.org/problemnew/show/1967
题解:答案一定在原图的最大生成森林上,否则一定不最优的。所以我们先做一遍最大生成树,对于每个询问,先判断是否在同一颗树上,不在直接输出-1,在的话我们用倍增预先求出点i向上2^j的信息,每组询问(x,y)的答案在(x,lca(x,,y))和(y,lca(x,y))里;
代码::
#include<cstdio> #include<algorithm> #define inf 2000000000 #define maxn 10010 using namespace std; template<class T>inline void read(T &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9')f|=(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=f?-x:x; return; } struct node { int u,v,w,next; inline bool operator<(const node&A)const{ return A.w<w; } }a[50010],e[20100]; int cnt,head[maxn],fa[maxn][17],bin[17],d[maxn][17],dep[maxn],f[maxn]; bool vis[maxn]; void ins(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;} int find(int x){return f[x]==x?x:f[x]=find(f[x]);} void dfs(int x) { vis[x]=true; for(int i=1;i<=16;i++) if(dep[x]<bin[i])break; else fa[x][i]=fa[fa[x][i-1]][i-1],d[x][i]=min(d[x][i-1],d[fa[x][i-1]][i-1]); for(int p=head[x];p;p=e[p].next) { int v=e[p].v; if(vis[v])continue; dep[v]=dep[x]+1;fa[v][0]=x;d[v][0]=e[p].w; dfs(v); } } int solve(int x,int y) { int mn=inf; if(dep[x]<dep[y])swap(x,y); int t=dep[x]-dep[y]; for(int i=0;i<=16;i++) if(t&bin[i])mn=min(mn,d[x][i]),x=fa[x][i]; for(int i=16;i>=0;i--) if(fa[x][i]!=fa[y][i]) mn=min(mn,min(d[x][i],d[y][i])),x=fa[x][i],y=fa[y][i]; if(x==y)return mn; else return min(mn,min(d[x][0],d[y][0])); } int main() { int n,m,x,y,t=0,q; read(n);read(m);bin[0]=1; for(int i=1;i<=16;i++)bin[i]=bin[i-1]<<1; for(int i=1;i<=m;i++) { read(a[i].u);read(a[i].v);read(a[i].w); } for(int i=1;i<=n;i++)f[i]=i; sort(a+1,a+1+m); for(int i=1;i<=m;i++) { int u=a[i].u,v=a[i].v; int f1=find(u),f2=find(v); if(f1!=f2) { f[f1]=f2; ins(u,v,a[i].w);ins(v,u,a[i].w); t++;if(t==n-1)break; } } for(int i=1;i<=n;i++)if(!vis[i])dfs(i); read(q); for(int i=1;i<=q;i++) { read(x);read(y); if(find(x)!=find(y))printf("-1\n"); else printf("%d\n",solve(x,y)); } return 0; }