Bond UVA - 11354

Bond UVA - 11354

题目大意:

n个点m条边的图,q次询问,找到一条从s到t的一条边,使所有边的最大危险系数最小。

题解:

使最大的危险系数尽量小,答案一定是最小生成树上的边。
为了快速回答询问,用LCA倍增法记录s和t到他们最近公共祖先的最大值。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;

const int N = 100005;
const int M = 500005;

int n,m;
int pa[N][21],dep[N],mx[N][21];

struct Edge{
    int u,v,next,w;
    Edge(){}
    Edge(int _u,int _v,int _w){
        u=_u; v=_v; w=_w;
    }
    bool operator < (const Edge & tp) const {
        return w < tp.w;
    }
}e[N*2],edge[M];
int head[N],ec,edgecnt;
void clearEdge(){ memset(head,0,sizeof(head)); ec=0; edgecnt=0; }
void add(int a,int b,int w){
    //D(a); D(b); D(w); E;
    ec++; e[ec].u=a; e[ec].v=b; e[ec].w=w;
    e[ec].next=head[a]; head[a]=ec;
}

struct UNSet{
    int pa[N];
    void init(int n){ for(int i=1;i<=n;i++)pa[i]=i; }
    int find(int x){
        if(pa[x]!=x) pa[x]=find(pa[x]);
        return pa[x];
    }
} unset;

void clearAll(){
    clearEdge();
    memset(pa,-1,sizeof(pa));
    memset(dep,0,sizeof(dep));
    memset(mx,-1,sizeof(mx));
}

void kruskal(){
    sort(edge+1,edge+1+edgecnt);
    unset.init(n); int cnt=0;
    for(int i=1;i<=edgecnt;i++){
        int x=unset.find(edge[i].u); 
        int y=unset.find(edge[i].v);
        if(x!=y){
            unset.pa[x]=y;
            add(edge[i].u,edge[i].v,edge[i].w);
            add(edge[i].v,edge[i].u,edge[i].w);
            if(++cnt==n-1) break;
        }
    }
}

void dfs(int u){
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(v==pa[u][0]) continue;
        pa[v][0]=u; dep[v]=dep[u]+1; mx[v][0]=e[i].w;
        dfs(v);
    }
}

void init(){
    for(int j=1;j<20;j++){
        for(int i=1;i<=n;i++){
            pa[i][j]=pa[pa[i][j-1]][j-1];
            mx[i][j]=max(mx[i][j-1],mx[pa[i][j-1]][j-1]);
        }
    }
}

int query(int a,int b){
    int ans=-1;
    if(dep[a]<dep[b]) swap(a,b);
    int cha=dep[a]-dep[b];
    for(int j=0;(1<<j)<=cha;j++){
        if(cha&(1<<j)){    //忘了这个,WA了一节课QwQ
            ans=max(ans,mx[a][j]);
            a=pa[a][j];
        }
    }
    if(a!=b){
        for(int j=20-1;j>=0;j--){
            if(pa[a][j]!=pa[b][j]){
                ans=max(ans,max(mx[a][j],mx[b][j]));
                a=pa[a][j]; b=pa[b][j];
            }
        }
        ans=max(ans,max(mx[a][0],mx[b][0]));    //Take care!
    }
    return ans;
}

int main(){
    freopen("a.in","r",stdin);
    int a,b,w,q;
    int cas=0;
    while(~scanf("%d%d",&n,&m) && (n||m)){
        if(cas)puts(""); cas++;
        clearAll();
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&w);
            edge[++edgecnt]=Edge(a,b,w);
        }
        kruskal();
        dfs(1);
        init();
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&a,&b);
            printf("%d\n",query(a,b));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值