货车运输 NOIP 2013 day1 t3

这个题目想A掉两个多月了,今天终于AC了,好开心 ^_^

题意是 有一个有n个点m条边的图,每次询问两个点路径上最小边权的最大值。

根据最大生成树的性质,先kruskal求出最大生成树,有g存储新的生成树。

然后倍增相当于在树上求出两两点的路径上最小边权的最大值。

之后通过dfs解决 f [ i ] [ 0 ] , w [ i ] [ 0 ] , d e p [ i ]

这个可以用 L C A 解决。

f [ i ] [ j ] 表示i的第 2 j 个父亲
w [ i ] [ j ] 表示i到第 2 j 个父亲这一段区间中最小边权的值。

调用的时候

f [ i ] [ j ] = f [ f [ i ] [ j 1 ] ] [ j 1 ] i 的第 2 j 个父亲=i的第 2 j 1 个父亲的 2 j 1 个父亲
w [ i ] [ j ] = m i n ( w [ i ] [ j 1 ] , w [ f [ i ] [ j 1 ] ] [ j 1 ] ) 同理

这个枚举必须先j再i,不然WA10.

之后都是常规的 L C A

先保证x的深度< y的深度,

然后跳y,跳到与x同样深度,之后x,y一起跳,如果 f [ x ] [ i ] = f [ y ] [ i ] 说明可能跳过了,要缩小i。直到 f [ x ] [ 0 ] = f [ y ] [ 0 ]

#include <bits/stdc++.h>
using namespace std ;
const int N = 10010 ;
const int M = 50010 ;
const int inf = 999999999 ;
struct edge{
    int from,to,w ;
}e[M];
struct node{
    int to,next,w ;
}g[M<<1];
int dad[N],head[N],dep[N],w[N][25],f[N][25],vis[N] ;
int n,m,Q,tot ;
int find(int x){
    return (dad[x]==x)?x:dad[x]=find(dad[x]) ;
} 
bool cmp(edge a,edge b){
    return a.w>b.w ;
}
void add(int x,int y,int w){
    g[++tot].to=y ;
    g[tot].w=w ;
    g[tot].next=head[x] ;
    head[x]=tot ;
}
void kruskal(){
    for (int i=1;i<=n;i++) dad[i]=i ;
    sort(e+1,e+m+1,cmp) ;
    for (int i=1;i<=m;i++){
        int X=find(e[i].from),Y=find(e[i].to) ;
        if (X!=Y){
            dad[X]=Y ;
            add(e[i].from,e[i].to,e[i].w) ;
            add(e[i].to,e[i].from,e[i].w) ;
        }
    }
}
void dfs(int rt){ //预处理 
    vis[rt]=true;
    for (int i=head[rt];i;i=g[i].next){
        int to=g[i].to;
        if (vis[to]) continue ;
        dep[to]=dep[rt]+1 ;
        w[to][0]=g[i].w ;
        f[to][0]=rt ;
        dfs(to) ;
    }
}
int lca(int x,int y){
    if (find(x)!=find(y)) return -1 ;
    int ans=inf ;
    if (dep[x]>dep[y]) swap(x,y) ;//保证x的深度<y的深度,跳y
    for (int i=20;i>=0;i--){
        if (dep[x]<=dep[f[y][i]]){
            ans=min(ans,w[y][i]) ;
            y=f[y][i] ;
        }
    }
    if (x==y) return ans ;
    for (int i=20;i>=0;i--){
        if (f[x][i]!=f[y][i]){
            ans=min(ans,min(w[x][i],w[y][i])) ;
            x=f[x][i] ;
            y=f[y][i] ;
        }
    }
    ans=min(ans,min(w[x][0],w[y][0])) ;
    return ans ;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w) ;
    kruskal() ;
    for (int i=1;i<=n;i++){
        if (!vis[i]){
            dep[i]=1 ;
            dfs(i);
            w[i][0]=inf ;
            f[i][0]=i ; 
        } 
    }
    for (int j=1;j<=20;j++){
        for (int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1] ;
            w[i][j]=min(w[i][j-1],w[f[i][j-1]][j-1]) ;
        }   
    }
    scanf("%d",&Q) ;
    for (int i=1;i<=Q;i++){
        int a,b ;
        scanf("%d%d",&a,&b) ;
        printf("%d\n",lca(a,b)) ;
    }
}

猜你喜欢

转载自blog.csdn.net/HQG_AC/article/details/81427681