UVA 11354 Bond
最小生成树,LCA,ST
题目
给出一张n个点m条边的无向图, 每条边有一个危险度,有q个询问, 每次给出两个点s、t,找一条路, 使得路径上的最大危险度最小。
思路
首先,我们可以发现,如果求一个最小生成树, 那么任意两点, 在生成树上有唯一路径, 而且这条路径上的最大危险值一定最小。
然后在最小生成树上做路径最小值的询问,处理出LCA,在用RMQ。
代码
#include<bits/stdc++.h>
#include<stdlib.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=100007;
typedef long long LL;
struct Edge
{
int from,to;
LL cost;
Edge(){}
Edge(int from,int to,LL cost){this->from=from,this->to=to,this->cost=cost;}
bool operator< (const Edge& a)const
{
return cost<a.cost;
}
} e[MAXN<<1];
vector<Edge> nG[MAXN];
int father[MAXN];
void init(int n)
{
for(int i=1; i<=n; i++)
{
father[i]=i;
}
}
int find(int x)
{
if(father[x]==x) return x;
else
{
return father[x]=find(father[x]);
}
}
void merge(int x, int y)
{
int fx=father[x], fy=father[y];
if(fx!=fy) father[fx]=fy;
}
void kruskal(int n,int m)
{
sort(e+1,e+2*m+1);init(n);
int cnt=0;
for(int i=1;i<=n;i++)
{
nG[i].clear();
}
for(int i=1; i<=2*m; i++)
{
Edge te=e[i];
if(find(te.from)!=find(te.to))
{
merge(te.from, te.to);
nG[te.from].push_back(Edge(te.from,te.to,te.cost));
nG[te.to].push_back(Edge(te.to,te.from,te.cost));
cnt++;
}
if(cnt==n-1)
{
break;
}
}
}
int parent[30][MAXN],depth[MAXN];
LL dis[30][MAXN];
//LCA
void dfs(int v, int f, int d)
{
parent[0][v] = f;
dis[0][v] = -1;
depth[v] = d;
for(int i=0; i<nG[v].size(); i++)
{
Edge nv = nG[v][i];
if(nv.to!=f)
dfs(nv.to, v, d+1);
else
dis[0][v] = nv.cost;
}
}
void init_lca(int n)
{
memset(dis, 0, sizeof dis);
memset(depth, -1, sizeof depth);
for(int i=1; i<=n; i++)
if(depth[i]<0)
dfs(i, -1, 0);
for(int k=0; k+1<30; k++)
{
for(int i=1; i<=n; i++)
{
if(parent[k][i]<0) parent[k+1][i] = dis[k+1][i] = -1;
else
{
parent[k+1][i] = parent[k][parent[k][i]];
dis[k+1][i] = max(dis[k][i], dis[k][parent[k][i]]);
}
}
}
}
LL lca(int u, int v)
{
if(depth[v] > depth[u]) swap(u, v);
LL ret = 0;
for(int i=0; i<30; i++){
if((depth[u]-depth[v]) >> i & 1) {
ret = max(ret, dis[i][u]);
u = parent[i][u];
}
}
if(u==v) return ret;
for(int i=30-1; i>=0; i--){
if(parent[i][u]!=parent[i][v]){
ret = max(ret, dis[i][u]);
ret = max(ret, dis[i][v]);
u = parent[i][u];v = parent[i][v];
}
}
ret = max(ret, dis[0][u]);
ret = max(ret, dis[0][v]);
return ret;
}
int main()
{
int n,m;int cas=0;
while(scanf("%d%d",&n,&m)==2)
{
for(int i=1; i<=2*m; i+=2)
{
int a,b;
LL c;
scanf("%d%d%lld",&a,&b,&c);
e[i].from=a,e[i].to=b,e[i].cost=c;
e[i+1].from=b,e[i+1].to=a,e[i+1].cost=c;
}
kruskal(n,m);
init_lca(n);
int q;scanf("%d",&q);
if(cas==0) cas=1;
else printf("\n");
while(q--)
{
int a,b;scanf("%d%d",&a,&b);
printf("%lld\n",lca(a,b));
}
}
return 0;
}