bzoj3732-Network

本文探讨了在无向图中进行多次询问时,如何高效地找到任意两点间经过的最长边最小值的问题。提出了三种解决方案,包括最小生成树上的倍增、LCT求最大边权及Kruskal重构树上的倍增LCA。通过具体代码实现,展示了第三种方法的详细步骤。
摘要由CSDN通过智能技术生成

题意

给出一个 \(n\) 个点 \(m\) 条边的无向图,\(q\) 次询问 \((x,y)\) 的所有路径中最长边最小是多少。

\(n,m,q\le 3\times 10^4\)

分析

题意明显是最小生成树上两点之间最大边权。有三种做法。当模板题玩一玩就好了。

第一种是简单的最小生成树上倍增,复杂度为 \(O(n\log n)\)

第二种是最小生成树上用lct求最大边权,复杂度为 \(O(n\log n)\)

第三种是kruskal重构树上倍增lca,复杂度为 \(O(n\log n)\)

代码

这是第三种做法。

#include<bits/stdc++.h>
using namespace std;
inline char nchar() {
    static const int bufl=1<<20;
    static char buf[bufl],*a,*b;
    return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
}
inline int read() {
    int x=0,f=1;
    char c=nchar();
    for (;!isdigit(c);c=nchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=nchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=3e4+1;
const int maxm=3e4+1;
const int maxj=15;
int n,m,q,tot;
struct edge {
    int x,y,w;
    inline bool operator < (const edge &a) const {return w<a.w;}
} e[maxm];
int f[maxn];
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
namespace tree {
    vector<int> g[maxn];
    int w[maxn],f[maxn][maxj],dep[maxn];
    inline void add(int x,int y) {g[x].push_back(y);}
    void dfs(int x,int fa) {
        dep[x]=dep[fa]+1;
        f[x][0]=fa;
        for (int j=1;j<maxj;++j) f[x][j]=f[f[x][j-1]][j-1];
        for (vector<int>::iterator it=g[x].begin();it!=g[x].end();++it) dfs(*it,x);
    }
    inline int lca(int x,int y) {
        if (dep[x]<dep[y]) swap(x,y);
        for (int j=maxj-1;j>=0;--j) if (dep[f[x][j]]>=dep[y]) x=f[x][j];
        if (x==y) return x;
        for (int j=maxj-1;j>=0;--j) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
        return f[x][0];
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    tot=n=read(),m=read(),q=read();
    for (int i=1;i<=m;++i) {
        int x=read(),y=read(),w=read();
        e[i]=(edge){x,y,w};
    }
    for (int i=1;i<(n<<1);++i) f[i]=i;
    sort(e+1,e+m+1);
    for (int i=1;i<=m;++i) {
        int &x=e[i].x,&y=e[i].y,&w=e[i].w;
        int fx=find(x),fy=find(y);
        if (fx!=fy) {
            f[fx]=f[fy]=++tot;
            tree::w[tot]=w;
            tree::add(tot,fx),tree::add(tot,fy);
        }
    }
    tree::dfs(tot,tot);
    while (q--) {
        int x=read(),y=read();
        int ans=tree::w[tree::lca(x,y)];
        printf("%d\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7295668.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值