ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

现在有 K个询问 (1 < = K < = 15,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output

 对每个询问,输出最长的边最小值是多少。

求出最小生成树并用树链剖分维护

查询时查找最小生成树上A,B两点间路径上的最大值

时间复杂度O(Klog2N)

#include<cstdio>
#include<vector>
#include<algorithm>
int n,m,k,p1,p2,p3;
struct edge{
    int from,to,w;
    edge(){}
    edge(int a,int b,int c){
        from=a;to=b;w=c;
    }
};
struct edge1{
    int to,w;
    edge1(int b,int c){
        to=b;w=c;
    }
};
bool operator<(edge a,edge b){
    return a.w<b.w;
}
int ms[15003];
int pa[15005],top[15005],sz[15005],dep[15005],son[15005],el[15005],id[15005],idp=1;
inline int getp(int a){
    while(a^ms[a])a=ms[a];
    return a;
}
inline bool merge(int a,int b){
    int c=getp(a),d=getp(b);
    if(c==d)return false;
    ms[c]=d;
    while(ms[a]^d)c=ms[a],ms[a]=d,a=c;
    while(ms[b]^d)c=ms[b],ms[b]=d,b=c;
    return true;
}
int tr[32769];
edge es[60001];
std::vector<edge1> vs[15005];
int ep=0;
int dfs1(int w,int pa1,int dp){
    pa[w]=pa1;
    sz[w]=1;
    dep[w]=dp;
    for(int i=vs[w].size()-1,u;i>=0;i--){
        if((u=vs[w][i].to)==pa1)continue;
        sz[w]+=dfs1(u,w,dp+1);
        if(!son[w])son[w]=u;
        else if(sz[u]>sz[son[w]])son[w]=u;
    }
}
int dfs2(int w,int tp,int wv){
    id[w]=idp++;
    el[id[w]]=wv;
    top[w]=tp;
    for(int i=vs[w].size()-1,u;i>=0;i--){
        if((u=vs[w][i].to)==pa[w])continue;
        if(u==son[w])dfs2(u,tp,vs[w][i].w);
    }
    for(int i=vs[w].size()-1,u;i>=0;i--){
        if((u=vs[w][i].to)==pa[w])continue;
        if(u==son[w])continue;
        dfs2(u,u,vs[w][i].w);
    }
}
inline int max(int a,int b){return a>b?a:b;}
inline void setv(int w,int v){
    w+=16384;
    tr[w]=v;
    for(w>>=1;w;w>>=1)tr[w]=max(tr[w+w],tr[w+w+1]);
}
void build(){
    for(int i=1;i<idp;i++)tr[i+16384]=el[i];
    for(int i=16383;i>0;i--)tr[i]=max(tr[i+i],tr[i+i+1]);
}
inline int getmax(int a,int b){
    int ans=0;
    for(a+=16383,b+=16385;a^b^1;a>>=1,b>>=1){
        if(~a&1)ans=max(ans,tr[a^1]);
        if(b&1)ans=max(ans,tr[b^1]);
    }
    return ans;
}
int ask(int x,int y){
    int a=top[x],b=top[y],c;
    int ans=0;
    while(a!=b){
        if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c;
        ans=max(ans,getmax(id[a],id[x]));
        x=pa[a];
        a=top[x];
    }
    if(id[x]<id[y])setv(id[x],0),ans=max(ans,getmax(id[x],id[y])),setv(id[x],el[id[x]]);
    else setv(id[y],0),ans=max(ans,getmax(id[y],id[x])),setv(id[y],el[id[y]]);
    return ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)ms[i]=i;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&p1,&p2,&p3);
        es[ep++]=edge(p1,p2,p3);
    }
    std::sort(es,es+ep);
    for(int i=0,a,b;i<ep;i++){
        if(merge(a=es[i].from,b=es[i].to)){
            vs[a].push_back(edge1(b,es[i].w));
            vs[b].push_back(edge1(a,es[i].w));
        }
    }
    dfs1(1,0,0);
    dfs2(1,0,0);
    build();
    for(int i=0;i<k;i++){
        scanf("%d%d",&p1,&p2);
        printf("%d\n",ask(p1,p2));
    }
    return 0;
}

 

posted on 2016-01-16 18:06  nul  阅读(226)  评论(0编辑  收藏  举报