zoukankan      html  css  js  c++  java
  • 【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增

    https://www.luogu.org/problemnew/show/P1967

    由题可知,我们走的路的边应尽可能大,所以通过$kruscal$建最大生成树的图,再树上倍增,注意可能有多棵树;

    #include <bits/stdc++.h>
    #define read read()
    #define up(i,l,r) for(register int i = (l);i <= (r);i++)
    #define down(i,l,r) for(register int i = (l);i >= (r);i--)
    #define traversal_vedge(i) for(register int i = head[u]; i ;i = e[i].nxt)
    #define ll long long
    using namespace std;
    int read
    {
        int x = 0, f = 1; char ch = getchar();
        while(ch < 48 || ch > 57) {if(ch == '-')f = -1; ch = getchar();}
        while(ch >=48 && ch <=57) {x = 10 * x + ch - 48;ch = getchar();}
        return x * f; 
    }
    const int N = 1e4+5,M = 5e5+5,inf = 0x3f3f3f3f;
    int n,m,q,f[N];
    struct kedge{
        int u,v,limit;
        bool operator < (const kedge &x) const{
            return limit > x.limit;
        }
    }ke[M<<1];
    
    struct edge{
        int v,limit,nxt;
    }e[M<<1];int tot,head[N];
    
    void build_tree(int u,int v,int w) {e[++tot] = (edge){v,w,head[u]}; head[u] = tot;}
    
    //-----------------------------------------------------------------
    int find(int i) {if(f[i] == i) return i;f[i] = find(f[i]);return f[i]; }
    void kruscal(){
        sort(ke+1,ke+m+1);
        up(i,1,n) f[i] = i;
        int cnt = 0;
        up(i,1,m)
        {
            if(cnt == n-1) break;
            if(find(ke[i].u) != find(ke[i].v))
            {
                f[f[ke[i].u]] = f[ke[i].v];
                cnt++;
                build_tree(ke[i].u,ke[i].v,ke[i].limit);
                build_tree(ke[i].v,ke[i].u,ke[i].limit);//debug ke[i].u -> ke[i].v;
            }
            else continue;
        }
    }
    //-----------------------------------------------------------------------
    
    int fa[N][15],mine[N][15],dep[N],vis[N];//debug 15 ->14
    
    void dfs(int u,int f,int w){
        vis[u] = 1;
        dep[u] = dep[f] + 1;
        fa[u][0] = f;
        mine[u][0] = w;
        for(int i = 1; (1<<i) <= dep[u]; i++)
        {
            fa[u][i] = fa[fa[u][i-1]][i-1];
            mine[u][i] = min(mine[u][i-1],mine[fa[u][i-1]][i-1]);
        }
        traversal_vedge(i)
        {
            int v = e[i].v;
            if(v == f) continue;
            dfs(v,u,e[i].limit);
        }
    }
    
    /*int LCA(int x,int y){
        if(dep[x] < dep[y]) swap(x,y);
        down(i,14,0)
        {
            if(dep[fa[x][i]] >= dep[y]) 
                x = fa[x][i];
        }
        if(x == y) return x;
        down(i,14,0)
        {
            if(fa[x][i] != fa[y][i])
            {
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        return fa[x][0];
    }*/
    //-----------------------------------------------------------------
    
    int query(int x,int y)
    {
        int ans = inf;
        if(dep[x] < dep[y]) swap(x,y);
        down(i,14,0)
        {
            if(dep[fa[x][i]] >= dep[y]) 
            {
                ans = min(ans,mine[x][i]);
                x = fa[x][i];
            }
        }
        if(x == y) return ans;
        down(i,14,0)
        {
            if(fa[x][i] != fa[y][i])
            {
                ans = min(ans,min(mine[x][i],mine[y][i]));
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        ans = min(ans,min(mine[x][0],mine[y][0]));
        return ans;
    }
    
    /*int query(int x,int lca){
        //if(x == lca) return 0x3f3f3f3f;
        int i = 0;
        while(dep[fa[x][i]] > dep[lca] ) i++;
        return mine[x][i];
    }*/
    
    void work(){
        kruscal();
        memset(mine,0x3f,sizeof(mine));
        //debug 未考虑多棵树
        up(i,1,n)
        {
            if(!vis[i])
            dfs(i,0,inf);
        } 
        q = read;
        while(q--)
        {
            int x = read, y = read;
            if(find(x) != find(y)) 
            {
                printf("-1
    ");
                continue;
            }
            //int lca = LCA(x,y);
            //ans = min(query(x,lca),query(y,lca));
            printf("%d
    ",query(x,y));
        }
    }
    
    void readdata()
    {
        n = read; m = read;
        up(i,1,m)
        {
            ke[i].u = read; ke[i].v = read; ke[i].limit = read;
        }
    }
    
    int main()
    {
        freopen("input21.txt","r",stdin);
        //freopen("output21.out","w",stdout);
        readdata();
        work();
        return 0;
    }

    最开始的写法之所以是错误的,是因为会多求一段,而我们只需要求到LCA就行;

  • 相关阅读:
    NOIP2018游记
    NOIP2018T1DAY1——Road(并查集做法??)
    UVA11021 Tribles——概率dp
    捡石头——(期望递推)
    USACO2008mar-gold牛跑步(第k短路:A-star)
    Java中的异常处理
    Java学习手册
    各种应用层注入手段整理 【转载】
    正则表达式学习
    Run-Time Check Failure #0,The value of ESP was not properly saved 错误解决
  • 原文地址:https://www.cnblogs.com/mzg1805/p/10418311.html
Copyright © 2011-2022 走看看