Uva 11354

Uva 11354

題意是給出n個點,m條邊的圖,並有q個詢問(s,t),輸出s到t的最右路徑下的最大邊權值。
用Kruskal先求出最小瓶頸生成樹,並深搜將其轉化爲有根樹,並在同時記錄下每個點的深度和父結點。計算出anc[i][j]以及maxcost[i][j],分別表示i的第2^j級祖先,i到其第2^j級祖先的最長邊長度,j=0時表示父節點。
那麼存在遞推關係anc[i][j]=anc[anc[i][j-1]][j-1],
maxcost[i][j]=max(maxcost[i][j-1],maxcost[anc[i][j-1]][j-1])。在n*lg(n)的時間裏處理出這兩個數組。
詢問時,輸入u,v。假設u深度比v深,先將u提升至與v同高,並在提升的過程中記錄下最大邊,再將u,v同時提升,直至他們有相同的父節點。具體實現見Query函數,利用二進制展開的方法,能將提升的過程在O(lgn)時間內實現。

#include<map>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#define LL long long
#define mm0(a) memset(a,0,sizeof(a))
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxe=1e5+5;
const int maxn=5e4+5;
const int Inf=1e9+5;
struct Edge{
    int from, to, next, dist;
    int id;
    Edge(){}
    Edge(int a,int b,int c,int d,int e):from(a), to(b), next(c), dist(d), id(e){}
    bool operator <(const Edge &rhs)const{
        return dist<rhs.dist;
    }
};
int n, m, ecnt;
int par[maxn], rak[maxn];
int head[maxn], intree[2*maxe];
int cost[maxn];
int anc[maxn][20], maxcost[maxn][20];
int L[maxn], F[maxn];
Edge edges[2*maxe];
void Init(int n){
    ecnt=0;
    mm(head,-1);
    mm0(intree);
    mm0(maxcost);
    mm0(rak);
    mm0(cost);
    for(int i=0;i<n;i++)
        par[i]=i;
}
void Add_Edge(int u,int v,int d){
    edges[ecnt]=Edge(u, v, head[u], d, ecnt);
    head[u]=ecnt++;
}
int Find(int x){
    if(par[x]==x) return x;
    par[x]=Find(par[x]);
    return par[x];
}
void Unite(int u, int v){
    int fu=Find(u);
    int fv=Find(v);
    if(fu==fv) return;
    if(rak[fu]<rak[fv]){
        par[fu]=fv;
    }else{
        par[fv]=fu;
        rak[fu]++;
    }
}
bool Cmp(Edge a,Edge b){
    return a.id<b.id;
}
void Kruskal(){
    sort(edges,edges+ecnt);
    for(int i=0;i<ecnt;i++){
        Edge &e=edges[i];
        int u=e.from;
        int v=e.to;
        int fu=Find(u);
        int fv=Find(v);
        if(fu==fv) continue;
        else{
            intree[e.id]=1;
            intree[e.id^1]=1;
            Unite(u,v);
        }
    }
    sort(edges,edges+ecnt,Cmp);
}
void Dfs(int u,int fa,int dep){
    L[u]=dep, F[u]=fa;
    for(int i=head[u];i!=-1;i=edges[i].next)
    if(intree[i]){
        Edge &e=edges[i];
        if(e.to==fa) continue;
        cost[e.to]=e.dist;
        Dfs(e.to, u, dep+1);
    }
}
void PreProcess(){
    for(int i=0;i<n;i++){
        anc[i][0]=F[i];
        maxcost[i][0]=cost[i];
        for(int j=1;(1<<j)<n;j++)
            anc[i][j]=-1;
    }
    for(int j=1;(1<<j)<n;j++){
        for(int i=0;i<n;i++)
        if(anc[i][j-1]!=-1){
            int x=anc[i][j-1];
            anc[i][j]=anc[x][j-1];
            maxcost[i][j]=max(maxcost[i][j-1],maxcost[x][j-1]);
        }
    }
}
int Query(int p,int q){
    if(L[p]<L[q]) swap(p,q);
    int log;
    for(log=1;(1<<log)<=L[p];log++); log--;
    int ans=-Inf;
    for(int i=log;i>=0;i--)
    if(L[p]-(1<<i)>=L[q]){
        ans=max(ans, maxcost[p][i]);
        p=anc[p][i];
    }
    if(p==q) return ans;
    for(int i=log;i>=0;i--)
    if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
        ans=max(ans, maxcost[p][i]); p=anc[p][i];
        ans=max(ans, maxcost[q][i]); q=anc[q][i];
    }
    ans=max(ans,cost[p]);
    ans=max(ans,cost[q]);
    return ans;
}
void solve(){

}
int main(){

//      freopen("matrix.in","r",stdin);//從in.txt中讀取數據
//      freopen("matrix.out","w",stdout);//輸出到out.txt文件
    int T;
    int u, v, d;
    int q;
    int cas=0;

    while(~scanf("%d%d",&n,&m)){
        if(cas++!=0) puts("");
        Init(n);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u, &v, &d);
            u--, v--;
            Add_Edge(u,v,d);
            Add_Edge(v,u,d);
        }
        Kruskal();
        Dfs(0,-1,0);
        PreProcess();
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            scanf("%d%d",&u,&v);
            u--, v--;
            printf("%d\n",Query(u,v));
        }
    }

    return 0;
}
發佈了54 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章