[NOIP 2013] trucking solution to a problem

answer:

First, the subject requires us to seek a minimum edge weight of all paths between two points, we have to do is to maximize the minimum edge right, we can get a map of the maximum spanning tree, so that the smallest edge weight must be the biggest. We can consider the reductio ad absurdum, if there is a minimum edge weight on the other path than the minimum right side of the path of the maximum spanning tree, then obviously we can not even another one of the larger side by side on the largest generation of broken maximum spanning tree tree (recommended drawing understand), and contradicts the definition of maximum spanning tree.

We can find the maximum spanning tree algorithm with $ Kruskal $, consider how to quickly find the path of two points, because the path between two points can be broken down into their path $ $ lca to these two points, we can select two points when evaluated interrogation of $ LCA $ binding multiplier way the shortest path is determined, specifically, two arrays $ f [i, j], dp [i, j] $ $ I $ node respectively the path to the node number and its $ 2 ^ j $ th ancestor node of the minimum weight.
Then there are:

$dp[i,j]=min(dp[i,j-1],dp[f[i,j-1],j-1])$

Both are over $ dfs $ can be obtained.

Details need attention: this figure may not be communicated, seeking $ dfs attention all over again when the maximum spanning tree dfs $.

Finally, attach the code:

#include<bits/stdc++.h>
using namespace std;
const int N=10005,M=50005,inf=(1<<30);

int c[N],ver[M],nxt[M],edge[M],head[N],d[N],f[N][20],dp[N][20];
int n,m,cnt,tot,t,q;
bool vis[N];

struct point{
    int u,v,len;
    bool operator < (const point &a)const{return a.len<len;}
}edge1[M];

int read(){
    int x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x;
}

int getfather(int x){return x==c[x] ? x : c[x]=getfather(c[x]);}
void add(int x,int y,int z){ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;}

void dfs(int x){
    vis[x]=1;
    for(int i=head[x],y;i;i=nxt[i]){
        if(vis[y=ver[i]]) continue;
        d[y]=d[x]+1,f[y][0]=x,dp[y][0]=edge[i];
        for(int j=1;j<=t;++j){
            f[y][j]=f[f[y][j-1]][j-1];
            dp[y][j]=min(dp[y][j-1],dp[f[y][j-1]][j-1]);
        }
        dfs(y);
    }
}

int LCA(int x,int y){
    int ans=inf;
    if(d[x]>d[y]) swap(x,y);
    for(int i=t;i>=0;--i){
        if(d[f[y][i]]>=d[x]){
            ans=min(ans,dp[y][i]);
            y=f[y][i];
        }
    }
    if(x==y) return ans;
    for(int i=t;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            ans=min(ans,min(dp[x][i],dp[y][i]));
            x=f[x][i],y=f[y][i];
        }
    }
    return ans=min(ans,min(dp[x][0],dp[y][0]));
}

int main(){
    n=read(),m=read();
    t=(int)(log(n)/log(2))+2;
    for(int i=1;i<=m;++i) edge1[++cnt].u=read(),edge1[cnt].v=read(),edge1[cnt].len=read();
    for(int i=1;i<=n;++i) c[i]=i;
    sort(edge1+1,edge1+1+cnt);
    for(int i=1;i<=cnt;++i){//Kruskal求最大生成树
        int x=edge1[i].u,y=edge1[i].v,z=edge1[i].len;
        int faa=getfather(x),fab=getfather(y);
        if(faa==fab) continue;
        c[fab]=faa;
        add(x,y,z),add(y,x,z);
    }
    for(int i=1;i<=n;++i) if(!vis[i]){d[i]=1,dfs(i);}
    q=read();
    for(int i=1,x,y;i<=q;++i){
        x=read(),y=read();
        int faa=getfather(x),fab=getfather(y);
        if(faa!=fab){printf("-1\n");continue;}//不在一个连通块内
        printf("%d\n",LCA(x,y));
    }
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/Asika3912333/p/11823473.html
Recommended