[BZOJ3732]Network

该博客讨论了一道图论问题,即在给定的无向图中,从A点到B点的所有路径中,找出最长边的最小值。题目给出了节点数量N、边数量M和询问次数K的限制,并描述了输入输出格式。博主提出解决方案是使用最小生成树Kruskal算法结合最近公共祖先(LCA)来求解,并对题目数据格式表达了不满。
摘要由CSDN通过智能技术生成

Time Limit: 10 Sec
Memory Limit: 128 MB

Description

给你 N N N个点的无向图 ( 1 &lt; = N &lt; = 15 , 000 ) (1 &lt;= N &lt;= 15,000) (1<=N<=15,000),记为: 1 … N 1…N 1N
图中有 M M M条边 ( 1 &lt; = M &lt; = 30 , 000 ) (1 &lt;= M &lt;= 30,000) (1<=M<=30,000),第 j j j条边的长度为: d j ( 1 &lt; = d j &lt; = 1 , 000 , 000 , 000 ) d_j ( 1 &lt; = d_j &lt; = 1,000,000,000) dj(1<=dj<=1,000,000,000).

现在有 K K K个询问 ( 1 &lt; = K &lt; = 20 , 000 ) (1 &lt; = K &lt; = 20,000) (1<=K<=20,000)
每个询问的格式是: A A A B B B,表示询问从 A A A点走到 B B B点的所有路径中,最长的边最小值是多少?

Input

第一行: N , M , K N, M, K N,M,K
2.. M + 1 2..M+1 2..M+1行: 三个正整数: X , Y , X, Y, X,Y, and D ( 1 &lt; = X &lt; = N ; 1 &lt; = Y &lt; = N ) D (1 &lt;= X &lt;=N; 1 &lt;= Y &lt;= N) D(1<=X<=N;1<=Y<=N). 表示 X X X Y Y Y之间有一条长度为 D D D的边。
M + 2.. M + K + 1 M+2..M+K+1 M+2..M+K+1行: 每行两个整数 A A A B B B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output

对每个询问,输出最长的边最小值是多少。

Sample Input

6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1

Sample Output

5
5
5
4
4
7
4
5

题解:
最小的最大值一定在最小生成树上(正论!)
那就直接kruskal完加个lca就行了

吐槽:
bzoj这道题的数据居然没有EOF,难受

#include<bits/stdc++.h>
#define LiangJiaJun main
using namespace std;
int n,m,k;
struct edge{
    int to,nt,w;
}e[200004];
struct Ds{
    int u,v,w;
}a[200004];
inline bool dex(Ds A,Ds B){return A.w<B.w;}
int ne,h[30004];
int f[30004],d[30004][24],fa[30004][24],depth[30004];
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
void add(int u,int v,int w){
     e[++ne].to=v;e[ne].w=w;e[ne].nt=h[u];
     h[u]=ne;
}
void dfs(int x){
     for(int i=1;i<=20;i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        d[x][i]=max(d[x][i-1],d[fa[x][i-1]][i-1]);
     }
     for(int i=h[x];i;i=e[i].nt){
         if(!depth[e[i].to]){
             depth[e[i].to]=depth[x]+1;
             d[e[i].to][0]=e[i].w;
             fa[e[i].to][0]=x;
             dfs(e[i].to);
         }
     }
}
int lca(int u,int v){
    if(depth[u]<depth[v])swap(u,v);
    int dva=depth[u]-depth[v];
    for(int i=0;i<=20;i++){
        if(dva&(1<<i))u=fa[u][i];
    }
    for(int i=20;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    if(u==v)return u;
    else return fa[u][0];
}
int ask(int x,int t){
    int dva=depth[x]-depth[t];
    int ans=0;
    for(int i=0;i<=20;i++){
        if(dva&(1<<i)){
            ans=max(ans,d[x][i]);
            x=fa[x][i];
        }
    }
    return ans;
}
int w33ha(){
    ne=0;
    memset(h,0,sizeof(h));
    memset(depth,0,sizeof(depth));
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
    sort(a+1,a+m+1,dex);
    for(int i=1;i<=m;i++){
        int p=Find(a[i].u),q=Find(a[i].v);
        if(p!=q){
            add(a[i].u,a[i].v,a[i].w);
            add(a[i].v,a[i].u,a[i].w);
            f[p]=q;
        }
    }
    for(int i=1;i<=n;i++){
        if(!depth[i]){
            depth[i]=1;
            dfs(i);
        }
    }
    while(k--){
        int a,b,t;
        scanf("%d%d",&a,&b);
        t=lca(a,b);
        printf("%d\n",max(ask(a,t),ask(b,t)));
    }
    return 0;
}
int LiangJiaJun(){
    scanf("%d%d%d",&n,&m,&k);
    w33ha();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值