• ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer


    传送门:https://nanti.jisuanke.com/t/31462

    本题是一个树上的问题:结点间路径问题。

    给定一个有M个结点的网格,并给出结点间建立墙(即拆除边)的代价。花费最小的代价,使得每一对结点之间的路径唯一。给出Q次询问:每次询问一对结点的路径长度。

    每一对结点之间存在路径,则图是连通的;路径唯一,则图是无环的。于是拆除边后的图是原图的一棵生成树。为使得拆除的代价尽可能小,这棵生成树应是最大生成树。通过Kruskal算法,可以求解最大生成树。

    之后,即是询问树结点对的路径长度。这个问题可以通过LCA算法求解。

    设结点u、v的LCA为结点k,即k=LCA(u,v),则dis(u,v)=dep[u]+dep[v]-2*dep[k]。此处通过倍增实现LCA。

    参考程序如下:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define MAX_N 300005
    
    priority_queue<pair<int, pair<int, int> > > edge;
    vector<int> adj[MAX_N];
    
    //Union Find.
    int fa[MAX_N];
    
    void init_dset(int n)
    {
        for (int i = 0; i < n; i++) fa[i] = i;
    }
    
    int find(int u)
    {
        if (fa[u] == u) return u;
        return fa[u] = find(fa[u]);
    }
    
    void unite(int u, int v)
    {
        int fu = find(u), fv = find(v);
        if (fu == fv) return;
        fa[fu] = fv;
    }
    
    bool same(int u, int v)
    {
        return find(u) == find(v);
    }
    
    //LCA.
    int pre[32][MAX_N]; //Ancestor Nodes.
    int dep[MAX_N]; //Depth of Nodes.
    
    void dfs(int u, int p)
    {
        pre[0][u] = p;
        for (int v : adj[u]) {
            if (v != p) {
                dep[v] = dep[u] + 1;
                dfs(v, u);
            }
        }
    }
    
    void init_lca(int n)
    {
        dfs(0, -1);
        for (int k = 0; k < 20; k++) {
            for (int v = 0; v < n; v++) {
                if (pre[k][v]) pre[k + 1][v] = pre[k][pre[k][v]];
            }
        }
    }
    
    int lca(int u, int v)
    {
        if (dep[u] > dep[v]) swap(u, v);
        for (int k = 0; k < 20; k++) {
            if ((dep[v] - dep[u]) & (1 << k)) v = pre[k][v];
        }
        if (u == v) return u;
        for (int k = 19; k >= 0; k--) {
            if (pre[k][u] != pre[k][v]) {
                u = pre[k][u];
                v = pre[k][v];
            }
        }
        return pre[0][u];
    }
    
    int main(void)
    {
        ios::sync_with_stdio(false);
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                string s, t;
                int a, b;
                cin >> s >> a >> t >> b;
                if (s[0] == 'D') {
                    int u = i * m + j;
                    int v = (i + 1) * m + j;
                    edge.push(make_pair(a, make_pair(u, v)));
                }
                if (t[0] == 'R') {
                    int u = i * m + j;
                    int v = i * m + j + 1;
                    edge.push(make_pair(b, make_pair(u, v)));
                }
            }
        }
        init_dset(n * m);
        while (!edge.empty()) {
            auto e = edge.top();
            edge.pop();
            int u = e.second.first;
            int v = e.second.second;
            if (!same(u, v)) {
                unite(u, v);
                adj[u].push_back(v);
                adj[v].push_back(u);
            }
        }
        init_lca(n * m);
        int q;
        cin >> q;
        while (q--) {
            int a, b, c, d;
            cin >> a >> b >> c >> d;
            a--; b--; c--; d--;
            int u = a * m + b;
            int v = c * m + d;
            int k = lca(u, v);
            cout << dep[u] + dep[v] - 2 * dep[k] << endl;
        }
    }
  • 相关阅读:
    使用灰层覆盖UI时,有事发生
    通过自定义ISAPI Filter来禁止敏感文件的访问
    静态链接库LIB和动态链接库DLL的区别 创建和示例
    深入剖析C++中的string类
    .net c# 序列化和反序列
    ASP.NET 状态服务 及 session丢失问题解决方案总结
    IWAM_账号的用途以及如何同步密码
    COM 组件设计与应用(一)起源及复合文件
    两种古老的WEB编程技术 CGI和ISAPI之间的区别
    Send MSMQ Messages Securely Across the Internet with HTTP and SOAP
  • 原文地址:https://www.cnblogs.com/siuginhung/p/9616207.html
Copyright © 2020-2023  润新知