UVA 11354 Bond

15 篇文章 0 订阅
6 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值