每日一题 P1967 [NOIP2013 提高组] 货车运输 最大生成树 LCA倍增
这道题虽然是蓝色题,但是其实不难想,代码量有点大。debug了很久,还是wa,最后发现又是小错误。
先用DSU+Kruskal跑最大生成树,然后用LCA倍增的方式,处理出一个点往上2^i步的点和这两个点之间所有边的最小值,然后就可以很方便的改改倍增的板子来求解了。
对板子的熟悉程度不够,导致了一些小bug,最后是对着别人代码看找出来的问题。
#include <bits/stdc++.h>
#define MAXN 500005
using namespace std;
struct EDGE
{
int to,next,w;
}edge[MAXN];int ptr;
int head[MAXN];
void add_edge(int u,int v,int w)
{
edge[++ptr].to=v;
edge[ptr].w=w;
edge[ptr].next=head[u];
head[u]=ptr;
}
void add(int a,int b,int w)
{
add_edge(a,b,w);
add_edge(b,a,w);
}
int dsu[MAXN];int n,m;
void init()
{
for(int i=0;i<MAXN;i++)
dsu[i]=i;
}
int fnd(int x)
{
if(dsu[x]==x)return x;
return dsu[x]=fnd(dsu[x]);
}
void merg(int x,int y)
{
dsu[fnd(x)]=fnd(y);
}
struct E
{
int a,b,w;
};
bool cmp(E a,E b)
{
return a.w>b.w;
}
vector<E> v;
void kruskal()
{
sort(v.begin(),v.end(),cmp);
for(int i=0;i<v.size();i++)
{
if(fnd(v[i].a)==fnd(v[i].b))continue;
add(v[i].a,v[i].b,v[i].w);
merg(v[i].a,v[i].b);
}
}
int dep[MAXN],f[MAXN][25],me[MAXN][25];
void dfs(int now,int fa)
{
for(int p=head[now]; p; p=edge[p].next)
{
int to=edge[p].to;
if(to==fa)continue;
dep[edge[p].to]=dep[now]+1;//计算深度
f[to][0]=now;
me[to][0]=edge[p].w;
dfs(to,now);
}
}
void dp()
{
//预处理 f[u][i] u结点往上走2^i次
for(int i=1; (1<<i)<=n; i++)
for(int u=1; u<=n; u++)
f[u][i]=f[f[u][i-1]][i-1],me[u][i]=min(me[u][i-1],me[f[u][i-1]][i-1]);//u结点往上走2^i次等于网上走两个2^(i-1)
}
int lca(int x,int y)
{
int ret=INT_MAX;
int p,t;
if(dep[x]<dep[y])
swap(x,y);//保证x比y大
for(p=0; (1<<p)<=dep[x]; p++);//算出dp最多往上走2的多少次
for(t=--p; t>=0; t--)//从x走到y同一层
if(dep[x]-(1<<t)>=dep[y])//不超过的话就往上走
ret=min(ret,me[x][t]),x=f[x][t];
if(x==y)
return ret;
for(t=p; t>=0; t--)//x和y一起走 不相等就往上走
if(f[x][t]!=f[y][t])
ret=min(ret,me[x][t]),x=f[x][t],ret=min(ret,me[y][t]),y=f[y][t];
return min(ret,min(me[x][0],me[y][0]));
}
int main()
{
init();
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,w;cin>>a>>b>>w;
v.push_back(E{a,b,w});
}
kruskal();
for(int i=1;i<=n;i++)
if(!dep[i])
dfs(i,0);
dp();
int q;cin>>q;
while(q--)
{
int a,b;cin>>a>>b;
if(fnd(a)!=fnd(b))cout<<-1<<endl;
else cout<<lca(a,b)<<endl;
}
}