zoukankan      html  css  js  c++  java
  • NOIP 2013 货车运输

    题目链接

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

    一眼看出思路,20分钟敲代码,40分钟调试

    一个小时一次提交AC了这道题

    首先有个结论

    最大生成树上两两之间的路径一定是最大的,如果存在不是,那么这颗树就不是最大生成树

    然后就树上倍增求最小边权就好了

    然后以后根节点的父亲可以设为0,然后一开始跳到同一深度的时候特判一下就好了

    然后注意一些细节,写在程序里面了

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 5e4 + 10;
    const int MAXM = 20;
    
    struct Edge{ int to, w, next; };
    Edge e[MAXN << 1];
    int head[MAXN], tot;
    
    int F[MAXN][MAXM + 5], data[MAXN][MAXM + 5]; //注意这里MAXM+5 
    int f[MAXN], vis[MAXN], d[MAXN], n, m;
    struct node
    {
        int u, v, w;
        bool operator < (const node& rhs) const
        {
            return w > rhs.w;
        }
    };
    vector<node> edges;
    
    void AddEdge(int from, int to, int w)
    {
        e[tot] = Edge{to, w, head[from]};
        head[from] = tot++;
    }
    
    void read(int& x)
    {
        int f = 1; x = 0; char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
        while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
        x *= f;
    }
    
    int find(int x)
    {
        if(f[x] == x) return x;
        return f[x] = find(f[x]);
    }
    
    void dfs(int u)
    {
        vis[u] = 1;
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(vis[v]) continue; //注意这里直接continue 
            d[v] = d[u] + 1; //先算d再递归下去 
            dfs(v);
            F[v][0] = u;
            data[v][0] = e[i].w; 
        }
    }
    
    int min_val(int u, int v)
    {
        int res = 1e9;
        if(d[u] < d[v]) swap(u, v);
        for(int j = MAXM; j >= 0; j--)
            if(F[u][j] && d[F[u][j]] >= d[v]) //注意这里要特判0 
            {
                res = min(res, data[u][j]); //注意这里一定是先统计再跳 
                u = F[u][j];
            }
        if(u == v) return res;
        for(int j = MAXM; j >= 0; j--)
            if(F[u][j] != F[v][j])
            {
                res = min(res, min(data[u][j], data[v][j]));
                u = F[u][j]; v = F[v][j];
            }
        return min(res, min(data[u][0], data[v][0]));
    }
    
    int main()
    {
        memset(head, -1, sizeof(head)); tot = 0;
        read(n); read(m);
        
        _for(i, 1, m)
        {
            int u, v, w; 
            read(u); read(v), read(w);
            edges.push_back(node{u, v, w});
        }
        
        sort(edges.begin(), edges.end());
        _for(i, 1, n) f[i] = i;    
        
        REP(i, 0, edges.size())
        {
            int u = edges[i].u, v = edges[i].v, w = edges[i].w;
            int fu = find(u), fv = find(v);
            if(fu != fv)
            {
                f[fu] = fv;
                AddEdge(u, v, w); AddEdge(v, u, w);
            }
        }
        
        _for(u, 1, n)
            if(!vis[u])
            {
                F[u][0] = 0; //这里把每个根的父亲设为0,在倍增的时候需要特判0 
                dfs(u);
            }
            
        _for(j, 1, MAXM)
            _for(u, 1, n)
            {
                F[u][j] = F[F[u][j-1]][j-1];
                data[u][j] = min(data[u][j-1], data[F[u][j-1]][j-1]);
            }
        
        int q; read(q);
        while(q--)
        {
            int u, v; read(u); read(v);
            if(find(u) != find(v)) puts("-1");
            else printf("%d
    ", min_val(u, v));
        }
        
        return 0;
    }
  • 相关阅读:
    zip 中文文件夹为空问题
    webview长按文本区域不显示文字放大镜等方法
    crash
    精疲力尽先生的造访
    告别忙碌的2017,迎来更加忙碌的2018
    传说中的59分!!
    为什么我一定吵不过女人?
    人挪活!
    低谷时,请读书!
    java小入门的感觉
  • 原文地址:https://www.cnblogs.com/sugewud/p/9880090.html
Copyright © 2011-2022 走看看