NOIP2013貨車運輸 計蒜客習題 蒜頭君運送寶藏

手畫樣例容易發現每次詢問所求答案爲路徑上的最小邊

而最大生成樹的最小邊一定是所有生成樹中最大的 且原圖的連通性不變

指定每個連通塊中的任意一個結點爲根建樹  可以發現每次詢問的貨車路徑經過他們的LCA

可以在求LCA的同時維護最小邊的信息 同樣用一個倍增數組 而判斷連通可以用並查集

半個週日都獻給這題了丂

點擊打開鏈接

#include<bits/stdc++.h>
using namespace std;
const int maxn=10001,maxm=50001,inf=0x3f3f3f3f;
struct e{int u,v,w; bool operator<(const e &a)const{return w>a.w;}}t[maxm];
struct edge{int v,w,nxt;}e[maxm<<1];
int p[maxn],fa[maxn],eid=0,anc[maxn][20],w[maxn][20],d[maxn],n,m,q,rst;
inline int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
inline void dfs(int u){
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(!d[v]){
            d[v]=d[u]+1;
            anc[v][0]=u;
            w[v][0]=e[i].w;
            dfs(v);
        }
    }
}
inline void pre(){
    memset(p,-1,sizeof(p));
    for(int i=1;i<=n;i++) fa[i]=i;
}
inline void init(){    
    for(int lv=1;(1<<lv)<=n;lv++)
    {
        for(int i=1;i<=n;i++)
        {
            anc[i][lv]=anc[anc[i][lv-1]][lv-1];
            w[i][lv]=min(w[anc[i][lv-1]][lv-1],w[i][lv-1]);//倍增維護最小值
        }
    }
}
inline int lca(int x,int y){
    int ans=inf;
    if(d[x]<d[y]) swap(x,y);
    int i,j;
    for(i=0;(1<<i)<=d[x];i++);
    i--;
    for(int j=i;j>=0;j--)
    {
        if(d[x]-d[y]>=(1<<j)){
            ans=min(ans,w[x][j]);   //往上跳並更新w[x][j]
            x=anc[x][j];
        }
    }
    if(x==y) return ans;
    for(j=i;j>=0;j--){
        if(anc[x][j]!=anc[y][j])
        {
            ans=min(ans,min(w[x][j],w[y][j]));  //同時兩個往上跳
            x=anc[x][j];
            y=anc[y][j];
        }
    }
    ans=min(ans,min(w[x][0],w[y][0]));  //一步到lca
    return ans;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&t[i].u,&t[i].v,&t[i].w);
    }
    sort(t+1,t+m+1);
    pre();
    rst=n;
    for(int i=1;i<=m;i++)
    {
        int u=t[i].u,v=t[i].v,w=t[i].w;
        int x=get(u),y=get(v);
        if(x!=y){
            fa[x]=y;
            rst--;
            e[eid].v=v;e[eid].w=w;e[eid].nxt=p[u];p[u]=eid++;
            e[eid].v=u;e[eid].w=w;e[eid].nxt=p[v];p[v]=eid++;
            if(rst==1) break;   //建圖
        }
    }
    for(int i=1;i<=n;i++)
        if(d[i]==0){
            d[i]=1;
            anc[i][0]=0;
            dfs(i);
        }
    init();
    cin>>q;
    int a,b;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&a,&b);
        if(get(a)!=get(b)){
            puts("-1");
        }
        else{
            printf("%d\n",lca(a,b));
        } 
    }
    return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章