BZOJ 3732: Network【最小生成树+LCA】

3732: Network

Time Limit: 10 Sec Memory Limit: 128 MB

Description

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).
现在有 K个询问 (1 < = K < = 20,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A 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

HINT

1 <= N <= 15,000
1 <= M <= 30,000
1 <= d_j <= 1,000,000,000
1 <= K <= 15,000

题解

这提要求我们求边长的最大值最小,所以我们需要满足两个条件,“最大值最小”很容易让人想到二分,但是这题显然不行,那么“最大值最小”还可以用最小生成树进行求解,正好适合这题,然后LCA一下就可以了。

贴上代码

#include<cstdio>
#include<algorithm>
#define MAXN 15005
using namespace std;
struct xcw{
    int x,y,z;
    bool operator <(const xcw b)const{return z<b.z;}
}a[2*MAXN]; 
int n,m,K,fa[MAXN],Dep[MAXN];
int tot,lnk[MAXN],nxt[2*MAXN],son[2*MAXN],W[2*MAXN];
int Fa[MAXN][30],F[MAXN][30];
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
void Add(int x,int y,int z){son[++tot]=y;W[tot]=z;nxt[tot]=lnk[x];lnk[x]=tot;}
void Kruskal(){
    int Now=0;
    for(int i=1;i<=m;i++){
        int x=get(a[i].x),y=get(a[i].y);
        if(x^y){
            fa[y]=x;
            Add(a[i].x,a[i].y,a[i].z);Add(a[i].y,a[i].x,a[i].z); 
            if(++Now==n-1) return;
        }
    }
}
void DFS(int x,int Lst,int D){
    Dep[x]=D;
    for(int j=lnk[x];j;j=nxt[j])
    if(son[j]^Lst) Fa[son[j]][0]=x,F[son[j]][0]=W[j],DFS(son[j],x,D+1);
}
void Rmq(){
    for(int i=1;i<=n;i++)
    for(int j=1;(1<<j)<n;j++) Fa[i][j]=-1;
    for(int j=1;(1<<j)<n;j++)
    for(int i=1,x;i<=n;i++) 
    if(Fa[i][j-1]^-1) x=Fa[i][j-1],F[i][j]=max(F[i][j-1],F[x][j-1]),Fa[i][j]=Fa[x][j-1];
}
int get(int p,int q){
    if(Dep[p]<Dep[q]) swap(p,q);
    int Log,sum=0;
    for(Log=0;(1<<Log)<Dep[p];Log++);Log--;
    for(int i=Log;i+1;i--) 
    if(Dep[Fa[p][i]]>=Dep[q]) sum=max(sum,F[p][i]),p=Fa[p][i];
    if(p==q) return sum;
    for(int i=Log;i+1;i--)
    if(Fa[p][i]^-1&&Fa[p][i]^Fa[q][i])
    sum=max(sum,F[p][i]),sum=max(sum,F[q][i]),p=Fa[p][i],q=Fa[q][i];
    sum=max(sum,F[p][0]);sum=max(sum,F[q][0]);
    return sum;
}
int main(){
//  freopen("prob.in","r",stdin);
//  freopen("prob.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+1+m);
    for(int i=1;i<=n;i++) fa[i]=i;
    Kruskal();DFS(1,0,1);Rmq();
    for(int i=1;i<=K;i++){
        int x,y;scanf("%d%d",&x,&y);
        printf("%d\n",get(x,y));
    }
    return 0;
}
posted @ 2018-04-10 11:13  XSamsara  阅读(154)  评论(0编辑  收藏  举报