uva 11354 Bond

/*
题目大意 给一个双向连通的图,回答若干个询问,每个询问包含一个起点s和一个终点t,
要求找到一个从s到t的路,使得路径所有边的最大危险系数最小

本题为瓶颈路
要支持快速询问,把信息组织成某种易于查询的结构

先求出最小生成树,快速求出maxcost[i][j]

*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = 50050;
const int maxm = 100010;
const int logmaxn = 20;
const int INF = 1000000000;

struct Edge
{
    int from,to,w;
    Edge(const int& from = 0,const int& to = 0,const int& w = 0):from(from),to(to),w(w) {}
    Edge(const Edge& rsh)
    {
        this->from = rsh.from;
        this->to = rsh.to;
        this->w = rsh.w;
    }
    bool operator < (const Edge& rsh ) const
    {
        return this->w < rsh.w;
    }
};

int n,m;
int root[maxn];
vector<Edge> edges;
vector<int> G[maxn],C[maxn];

// 并查集
void init_set(int n)
{
    for(int i = 0 ; i < n ; i++)
    {
        root[i] = i;
        G[i].clear();
        C[i].clear();
    }
}

int find_set(int x)
{
    if(x != root[x])
    {
        root[x] = find_set(root[x]);
    }
    return root[x];
}

void union_set(int a,int b)
{
    int x = find_set(a);
    int y = find_set(b);
    if(x != y)
    {
        root[x] = y;
    }
}

void MST()
{
    sort(edges.begin(),edges.end());
    for(int i = 0 ; i < edges.size() ; i++)
    {
        int from = edges[i].from;
        int to = edges[i].to;
        int w = edges[i].w;
        if(find_set(from) != find_set(to))
        {
            union_set(from,to);
            G[from].push_back(to);
            C[from].push_back(w);
            G[to].push_back(from);
            C[to].push_back(w);
        }
    }
}

struct LCA
{
    int n;
    int fa[maxn];//i的父亲编号
    int cost[maxn];//i到父亲节点的距离
    int L[maxn];//i节点的深度
    int anc[maxn][logmaxn]; //节点i到第2^j级祖先的编号
    int maxcost[maxn][logmaxn];//节点i与第2^j级祖先之间的路径上的最大权值

    void preprocess() //预处理
    {

        for(int i = 0 ; i < n ; i++)
        {
            anc[i][0] = fa[i];
            maxcost[i][0] = cost[i];
            for(int j = 1 ; (1 << j) < n ; j++)
            {
                anc[i][j] = -1;
            }
        }

        for(int j = 1 ; (1 << j) < n ; j++)
        {
            for(int i = 0 ; i < n ; i++)
            {
                if(anc[i][j-1] != -1)
                {
                    int a = anc[i][j-1];
                    anc[i][j] = anc[a][j-1];
                    maxcost[i][j] = max(maxcost[i][j-1],maxcost[a][j-1]);
                }
            }
        }
    }

    int query(int p,int q)
    {
        int log;
        if( L[p] < L[q]) swap(p,q);
        for(log = 1 ; (1 << log) <= L[p] ; log++);
        log--;

        int ans = -INF;
        for(int i = log ; i >= 0 ; i--)
        {
            if(L[p] - (1<<i) >= L[q])
            {
                ans = max(ans,maxcost[p][i]);
                p = anc[p][i];
            }
        }

        if(p == q) // LCA 为p
        {
            return ans;
        }

        for(int i = log ; i >= 0 ; i--)
        {
            if(anc[p][i] != -1 && anc[p][i] != anc[q][i])
            {
                ans = max(ans,maxcost[p][i]);
                p = anc[p][i];
                ans = max(ans,maxcost[q][i]);
                q = anc[q][i];
            }
        }

        ans = max(ans,cost[p]);
        ans = max(ans,cost[q]);
        return ans;// LCA 为fa[p]也等于fa[q]
    }
};

LCA solver;


void dfs(int u,int fa,int level)
{
    solver.L[u] = level;
    for(int i = 0 ; i < G[u].size() ; i++)
    {
        int v = G[u][i];
        if(v != fa)
        {
            solver.fa[v] = u;
            solver.cost[v] = C[u][i];
            dfs(v,u,level+1);
        }
    }
}

void init()
{
    edges.clear();
    init_set(n);
}

int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int kcase = 0;
    while(scanf("%d %d",&n,&m) != EOF)
    {
        init();
        int from,to,w;
        for(int i = 0 ; i < m ; i++)
        {
            scanf("%d %d %d",&from,&to,&w);
            from--;
            to--;
            edges.push_back(Edge(from,to,w));
        }
        MST();
        solver.n = n;
        dfs(0,-1,0);

        solver.preprocess();
        if(++kcase != 1) printf("\n");
        int Q;
        scanf("%d",&Q);
        while(Q--)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            printf("%d\n",solver.query(x-1,y-1));
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值