zoukankan      html  css  js  c++  java
  • [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 '
    '
    #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
    ");
                continue;
            }
            int lca=LCA(l,r);
            int res=min(search(l,lca),search(r,lca));
            printf("%d
    ",res);
        }
    }
    /*
    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    */
    View Code
    Codeforces ID:Anonytt QQ: 847399102 可以添加&关注
  • 相关阅读:
    第二次项目冲刺(Beta阶段)--第六天
    Struts2+Hibernate简单整合
    Struts中Action的相关知识点
    struts基础配置
    servlet基础及过滤器简介
    JSP中验证码问题
    mybatis中插入数据(id为主键的情况)以及查询数据
    Mybatis基础配置及使用
    JDBC访问数据库
    Mysql中的一些基本操作
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13577589.html
Copyright © 2011-2022 走看看