HDU多校第五场 P7187(分层图建虚拟原点)()

Slipper

&ebsp;题意: 我们知道有\(n\)个节点,有\(n – 1\)条边,所有的点形成了一棵树,每一个点到下一个点都有代价\(cc\),我们也有一个操作,可以将满足\(\left\vert depth_i – depth_j\right\vert = k\)的所有点联通,连起来的新的边的代价是\(c\),要我们求从出发点到目的地的最小代价是多少。
 思路:因为不太好处理\(\left\vert depth_i – depth_j\right\vert = k\)这个条件,那我们就要选择将每一个深度都建出一个分层图,然后再每一个分层图中都建立两个虚拟原点,分别连向所有满足\(\left\vert depth_i – depth_j\right\vert = k\)的所有点。这样我们只需要用\(dijkstra\)跑一遍就可以求出答案了。

i64 w[N * 3];
int ne[N * 3], e[N * 3], h[N * 3];
i64 dist[N * 3];
int dep[N];
bool st[N * 3];

void solve() {
    int n, m, c;
    scanf("%d", &n);
        
    int mxd = 0, idx = 0;
    
    for (int i = 0; i <= n + 2; i ++ ) dep[i] = 0;

    for (int i = 0; i <= 3 * n + 10; i ++ )
        h[i] = -1, st[i] = 0, dist[i] = MX;
    
    auto add = [&] (int a, int b, i64 v) {
        w[idx] = v, e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
    };
    
    for (int i = 1; i < n; i ++ ) {
        int u, v;
        i64 cc;
        scanf("%d%d%lld", &u, &v, &cc);
        add(u, v, cc);
        add(v, u, cc);
    }

    scanf("%d%d", &m, &c);    

    std::function<void(int, int, int)> dfs1 = [&] (int u, int fa, int depth) {  
        dep[u] = depth;    
        mxd = std::max(mxd, depth);
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (v == fa) continue;
            dfs1(v, u, depth + 1);
        }
    };

    dfs1(1, 0, 1);
    std::vector<int> G[mxd + m + 1];

    for (int i = 1; i <= n; i ++ ) {
        G[dep[i]].push_back(i);
    }

    for (int i = 1; i <= mxd; i ++ ) {
        for (auto& adj : G[i]) add(adj, 1 + n + i, c);
        for (auto& adj : G[i + m]) add(n + i + 1, adj, 0);
        for (auto& adj : G[i]) add(n * 2 + i + 1, adj, 0);
        for (auto& adj : G[i + m]) add(adj, 1 + n * 2 + i, c);
    }
    
    int s, d;
    scanf("%d%d", &s, &d);

    auto dijkstra = [&] () -> i64 {
        dist[s] = 0;
        std::priority_queue<std::pair<i64, int>, std::vector<std::pair<i64, int>>, std::greater<std::pair<i64, int>>> q;
        q.push(std::make_pair(0, s));

        while(q.size()) {
            std::pair<i64, int> t = q.top();
            q.pop();
            int ver = t.second;
            if (st[ver]) continue;
            st[ver] = true;

            for (int i = h[ver]; ~i; i = ne[i]) {
                int v = e[i];
                if (dist[v] > dist[ver] + w[i]) {
                    dist[v] = dist[ver] + w[i];
                    q.push({dist[v], v});
                }
            }
        }
        return dist[d] == MX ? -1 : dist[d];
    };
    printf("%lld\n", dijkstra());
}
————————

Slipper

&ebsp;题意: 我们知道有\(n\)个节点,有\(n – 1\)条边,所有的点形成了一棵树,每一个点到下一个点都有代价\(cc\),我们也有一个操作,可以将满足\(\left\vert depth_i – depth_j\right\vert = k\)的所有点联通,连起来的新的边的代价是\(c\),要我们求从出发点到目的地的最小代价是多少。
 思路:因为不太好处理\(\left\vert depth_i – depth_j\right\vert = k\)这个条件,那我们就要选择将每一个深度都建出一个分层图,然后再每一个分层图中都建立两个虚拟原点,分别连向所有满足\(\left\vert depth_i – depth_j\right\vert = k\)的所有点。这样我们只需要用\(dijkstra\)跑一遍就可以求出答案了。

i64 w[N * 3];
int ne[N * 3], e[N * 3], h[N * 3];
i64 dist[N * 3];
int dep[N];
bool st[N * 3];

void solve() {
    int n, m, c;
    scanf("%d", &n);
        
    int mxd = 0, idx = 0;
    
    for (int i = 0; i <= n + 2; i ++ ) dep[i] = 0;

    for (int i = 0; i <= 3 * n + 10; i ++ )
        h[i] = -1, st[i] = 0, dist[i] = MX;
    
    auto add = [&] (int a, int b, i64 v) {
        w[idx] = v, e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
    };
    
    for (int i = 1; i < n; i ++ ) {
        int u, v;
        i64 cc;
        scanf("%d%d%lld", &u, &v, &cc);
        add(u, v, cc);
        add(v, u, cc);
    }

    scanf("%d%d", &m, &c);    

    std::function<void(int, int, int)> dfs1 = [&] (int u, int fa, int depth) {  
        dep[u] = depth;    
        mxd = std::max(mxd, depth);
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (v == fa) continue;
            dfs1(v, u, depth + 1);
        }
    };

    dfs1(1, 0, 1);
    std::vector<int> G[mxd + m + 1];

    for (int i = 1; i <= n; i ++ ) {
        G[dep[i]].push_back(i);
    }

    for (int i = 1; i <= mxd; i ++ ) {
        for (auto& adj : G[i]) add(adj, 1 + n + i, c);
        for (auto& adj : G[i + m]) add(n + i + 1, adj, 0);
        for (auto& adj : G[i]) add(n * 2 + i + 1, adj, 0);
        for (auto& adj : G[i + m]) add(adj, 1 + n * 2 + i, c);
    }
    
    int s, d;
    scanf("%d%d", &s, &d);

    auto dijkstra = [&] () -> i64 {
        dist[s] = 0;
        std::priority_queue<std::pair<i64, int>, std::vector<std::pair<i64, int>>, std::greater<std::pair<i64, int>>> q;
        q.push(std::make_pair(0, s));

        while(q.size()) {
            std::pair<i64, int> t = q.top();
            q.pop();
            int ver = t.second;
            if (st[ver]) continue;
            st[ver] = true;

            for (int i = h[ver]; ~i; i = ne[i]) {
                int v = e[i];
                if (dist[v] > dist[ver] + w[i]) {
                    dist[v] = dist[ver] + w[i];
                    q.push({dist[v], v});
                }
            }
        }
        return dist[d] == MX ? -1 : dist[d];
    };
    printf("%lld\n", dijkstra());
}