[NOIP2013]货车运输 (最大生成树+倍增RMQ数组的结合)

题目链接:https://nanti.jisuanke.com/t/T2015

题意:给你n个点,m条双向边,并告诉你每条边的u,v,w。再给你q次询问,每次询问查询x和y之间路径的w的最小值(让w尽可能大)。

解法:根据Kruskal算法的性质可以知道,按排序从大到小即是最大生成树,所以我们想这个题目的时候就要从性质入手,题目要求的是每条边的w的最小值尽可能最大,所以我们可以构造一个最大生成树建立新图,然后结合对于倍增数组的理解,来询问2点间的最小值。注意该题可能构造出一个森林,所以需要用并查集判是否在一个树上,如果不是的话直接输出-1即可。

AC代码:

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int n,m,f[maxn];
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
struct node{
    int u,v,w;
}eg[maxn<<2];
bool cmp(node a,node b){
    return a.w>b.w;
}
inline int find(int x){
    while(x!=f[x]) x=f[x]=f[f[x]];
    return x;
}
inline void kruskal(){
    int eu,ev,cnt=0;
    sort(eg+1,eg+m+1,cmp);
    for(int i=1;i<=m;i++){
        eu=find(eg[i].u),ev=find(eg[i].v);
        if(eu==ev) continue;
        int u=eg[i].u,v=eg[i].v,w=eg[i].w;
        add(u,v,w);add(v,u,w);
        f[ev]=eu;
        if(++cnt==n-1) break;
    }
}
int fa[maxn][40],depth[maxn];
int rmq[maxn][40];
bool vis[maxn];
void dfs(int u,int step){
    depth[u]=step;vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to,w=edge[i].w;
        if(vis[v]) continue;
        fa[v][0]=u;
        rmq[v][0]=w;
        dfs(v,step+1);
    }
}
void bz(){
    for(ll j=1;j<=19;j++){
        for(ll i=1;i<=n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            rmq[i][j]=min(rmq[i][j-1],rmq[fa[i][j-1]][j-1]);
        }
    }
}
ll LCA(ll u,ll v){
    if(depth[u]<depth[v]) swap(u,v);
    ll dc=depth[u]-depth[v];
    for(ll i=0;i<30;i++){
        if((1<<i)&dc){
            u=fa[u][i];
        }
    }
    if(u==v) return u;
    for(ll i=29;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    u=fa[u][0];
    return u;
}
int search(int u,int v){
    if(depth[u]<depth[v]) swap(u,v);
    int dc=depth[u]-depth[v];    
    int ans=INF;
    for(int i=0;i<30;i++){
        if((1<<i)&dc){
            ans=min(ans,rmq[u][i]);
            u=fa[u][i];
        }
    }
    if(u==v) return ans;
}

int main(){
    scanf("%d%d",&n,&m);    
    mem(rmq,INF);
    mem(head,-1);
    rep(i,1,n) f[i]=i;
    rep(i,1,m){
        int u,v,w;
        scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);
    }
    kruskal();
    dfs(1,1);
    bz();
    int t;scanf("%d",&t);
    while(t--){
        int l,r;cin>>l>>r;
        if(find(l)!=find(r)){
            printf("-1\n");
            continue;
        }
        int lca=LCA(l,r);
        int res=min(search(l,lca),search(r,lca));
        printf("%d\n",res);
    }
}
/*
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
*/
View Code

 

posted @ 2020-08-28 15:04  Anonytt  阅读(101)  评论(0编辑  收藏  举报