[2020多校联考]小Y的图

2020.11.21

解法

连接两个点的那条最大值最小的路径一定在最小生成树上,而又要查询这个最大值是多少,那么就想到建出克鲁斯卡尔重构树。由于可能不连通,所以最后建出来的实际上是重构森林,记得要把每个连通块都遍历到。

对于节点的连通性,直接用之前维护好的并查集就好了,不连通就输出-1,连通的话再在重构树内倍增找LCA,最后输出LCA的权值(该节点所表示的边的边权)。

#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 300007
 
inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}
 
struct E{
    int next,to;
}e[N<<2];
struct E_{
    int u,v,dis;
    E_(int u=0,int v=0,int dis=0):u(u),v(v),dis(dis){}
    bool operator <(const E_ x) const{
        return dis<x.dis;
    }
}L[N];
int n,m,Q,fa[N<<1],f[N<<1][20],val[N<<1],head[N<<1],cnt=0,dep[N<<1];
 
inline int find(int x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
 
inline void add(int id,int to){
    e[++cnt]=(E){head[id],to};
    head[id]=cnt;
}
 
bool vis[N<<1],tag[N<<1];
void dfs(int u){
    for(int i=1;i<20;i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]) continue;
        dep[v]=dep[u]+1,vis[v]=1;
        dfs(v);
    }
}
 
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline int Lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=19;~i;i--)
        if(dep[f[u][i]]>=dep[v])
            u=f[u][i];
    if(u==v) return u;
    for(int i=19;~i;i--)
        if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
    return f[u][0];
}
 
int main(){
//  freopen("graph.in","r",stdin);
//  freopen("graph.out","w",stdout);
    n=read(),m=read(),Q=read();
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
        L[i].u=read(),L[i].v=read(),L[i].dis=read();
    sort(L+1,L+1+m);
    int r=0;
    for(int i=1;i<=m;i++){
        int u=L[i].u,v=L[i].v;
        int fa_x=find(u),fa_y=find(v);
        if(fa_x==fa_y) continue;
        ++n;
        fa[n]=fa[fa_x]=fa[fa_y]=n;
        f[n][0]=f[fa_x][0]=f[fa_y][0]=n;
        add(n,fa_x); add(n,fa_y);
        val[n]=L[i].dis;
        if((++r)==n-1) break;
    }
    for(int i=n;i;i--)
        if(!vis[i]) dep[i]=vis[i]=1,dfs(i);
    while(Q--){
        int u=read(),v=read();
        if(find(u)!=find(v)) printf("-1\n");
        else{
            int lca=Lca(u,v);
            printf("%d\n",val[lca]);
        }
    }
}
posted @ 2020-11-23 14:38  Kreap  阅读(85)  评论(0编辑  收藏  举报