建树方法
在克鲁斯卡尔求最短路的基础上对原来的图进行一定的修改,与克鲁斯卡尔求最短路的区别在于每当找到一条树边时,将其变成一个点,这个点连接这条边连接的两个联通块(的根节点),然后就可以得到一棵树,这棵树的叶子结点,其余节点都是树边,权值就是树边的长度。
性质
可以发现,这棵树上的某棵子树的根节点是这棵子树的多有点的权值的最大值,如果要求某两个点的路径上的最大边权的最小值,求它们在这棵树上的LCA的权值即可。
例题(BZOJ 3732 Network)
给出一张无向图,多次询问A点到B点的所有路径中,最长的边的最小值是多少。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 30010
using namespace std;
int n,m,k,fa[N],tt,gen,size[N],son[N],top[N];
struct Bn
{
int u,v,quan;
bool operator < (const Bn &u) const
{
return quan<u.quan;
}
}bn[N];
struct Node
{
int quan,ls,rs,fa,size,deep;
}node[N];
inline int ff(int u){return u==fa[u]?u:fa[u]=ff(fa[u]);}
void dfs(int now)
{
if(!now) return;
node[now].size=1;
node[node[now].ls].deep=node[node[now].rs].deep=node[now].deep+1;
dfs(node[now].ls),dfs(node[now].rs);
node[now].size+=node[node[now].ls].size;
node[now].size+=node[node[now].rs].size;
if(node[now].size>1)
son[now]= node[node[now].ls].size>node[node[now].rs].size?node[now].ls:node[now].rs;
}
void Dfs(int now)
{
if(!son[now]) return;
if(son[now]==node[now].rs) swap(node[now].ls,node[now].rs);
top[node[now].ls]=top[now];
top[node[now].rs]=node[now].rs;
Dfs(node[now].ls),Dfs(node[now].rs);
}
inline int lca(int u,int v)
{
for(;top[u]!=top[v];)
{
if(node[top[u]].deep<node[top[v]].deep) swap(u,v);
u=node[top[u]].fa;
}
return node[u].deep>node[v].deep?v:u;
}
int main()
{
int i,j,p,q;
cin>>n>>m>>k;
tt=n;
for(i=1;i<=m;i++)
scanf("%d%d%d",&bn[i].u,&bn[i].v,&bn[i].quan);
sort(bn+1,bn+m+1);
for(i=1;i<=n;i++) fa[i]=i;
for(i=1;i<=m;i++)
{
p=ff(bn[i].u),q=ff(bn[i].v);
if(p==q) continue;
node[++tt].ls=p;
node[tt].rs=q;
node[tt].quan=bn[i].quan;
node[p].fa=node[q].fa=tt;
fa[p]=fa[q]=tt;
fa[tt]=tt;
}
gen=ff(1);
top[gen]=gen;
node[gen].deep=1;
dfs(gen);
Dfs(gen);
for(i=1;i<=k;i++)
{
scanf("%d%d",&p,&q);
printf("%d\n",node[lca(p,q)].quan);
}
}
例题2 [NOI2018]归程
代码
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define ll long long
#define P pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
#define N 400100
using namespace std;
ll n,m,T,faz[N],tt,d[N],fa[N][20],h[N],Q,K,S,last;
P tmp;
struct Bn
{
ll u,v,a;
bool operator < (const Bn &u) const
{
return a>u.a;
}
}bn[N];
priority_queue<P,vector<P>,greater<P> >pq;
vector<P>to[N];
ll ff(ll u){return u==faz[u]?u:faz[u]=ff(faz[u]);}
inline ll find(ll u,ll v)
{
ll i,t;
for(i=19;i>=0;i--)
{
t=fa[u][i];
if(h[t]>v) u=t;
}
return u;
}
int main()
{
ll i,j,p,q,t;
scanf("%lld",&T);
while(T--)
{
last=0;
memset(d,0x3f,sizeof(d));
memset(fa,0,sizeof(fa));
scanf("%lld%lld",&n,&m);
tt=n;
for(i=1;i<2*n;i++) faz[i]=i;
for(i=1;i<=m;i++)
{
scanf("%lld%lld%lld%lld",&bn[i].u,&bn[i].v,&t,&bn[i].a);
to[bn[i].u].push_back(mp(bn[i].v,t));
to[bn[i].v].push_back(mp(bn[i].u,t));
}
d[1]=0;
pq.push(mp(0,1));
for(;!pq.empty();)
{
tmp=pq.top();
pq.pop();
p=tmp.fi,q=tmp.se;
if(d[q]<p) continue;
for(i=0;i<to[q].size();i++)
{
t=to[q][i].fi;
if(p+to[q][i].se>=d[t]) continue;
d[t]=p+to[q][i].se;
pq.push(mp(d[t],t));
}
}
sort(bn+1,bn+m+1);
for(i=1;i<=m;i++)
{
p=ff(bn[i].u),q=ff(bn[i].v);
if(p==q) continue;
tt++;
h[tt]=bn[i].a;
d[tt]=min(d[p],d[q]);
fa[p][0]=fa[q][0]=tt;
faz[p]=faz[q]=tt;
}
for(i=1;(1 << i)<=tt;i++)
{
for(j=1;j<=tt;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
scanf("%lld%lld%lld",&Q,&K,&S);
for(i=1;i<=Q;i++)
{
scanf("%lld%lld",&p,&q);
p=(p+K*last-1)%n+1;
q=(q+K*last)%(S+1);
p=find(p,q);
printf("%lld\n",d[p]);
last=d[p];
}
for(i=1;i<=n;i++) to[i].clear();
}
}