2022暑期hdu5

3 Slipper

题解

设树的深度为d,在第i层(1<=i<=d)和第i+1层中新增两个点l_i,r+i,l_i连向所有第i+1层的点,r_i连向所有第i层 的点,对于原来树中所有的点,向l_{dep+k-1}连一条权为p单向边,向r_{dep_u-k)连一条权值为p的单向边,在修改后的图中跑dijkstra求s到t的最短路即可,复杂度O(nlogn)

标程

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using std::max, std::priority_queue, std::pair;
using ll = long long;

const int maxn = 1e6 + 5;
int e[maxn << 3][3], head[maxn << 2], tot = -1;
int dep[maxn << 2], maxdep = 0, n = 0, k = 0, p = 0, s = 0, t = 0;

void addEdge(int u, int v, int w) {
    e[++tot][0] = v;
    e[tot][1] = head[u];
    e[tot][2] = w;
    head[u] = tot;
}

void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    maxdep = max(maxdep, dep[u]);
    for (int i = head[u]; ~i; i = e[i][1]) {
        if (e[i][0] == fa)
            continue;
        dfs(e[i][0], u);
    }
}

ll dis[maxn << 2];
bool vis[maxn << 2];
void dijkstra() {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    priority_queue<pair<ll, int>> pq;
    pq.emplace(0, s);
    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();
        if (vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; ~i; i = e[i][1]) {
            int v = e[i][0], w = e[i][2];
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pq.emplace(-dis[v], v);
            }
        }
    }
}

void solve() {
    memset(head, -1, sizeof(head));
    tot = -1, maxdep = 0;
    scanf("%d", &n);
    int u = 0, v = 0, w = 0;
    for (int i = 1; i <= n - 1; ++i) {
        scanf("%d %d %d", &u, &v, &w);
        addEdge(u, v, w), addEdge(v, u, w);
    }
    dep[0] = -1;
    dfs(1, 0);
    scanf("%d %d", &k, &p);
    for (int i = 1; i <= n; ++i) {
        if (dep[i] != 0)
            addEdge(n + 2 * dep[i] - 1, i, p);
        if (dep[i] != maxdep)
            addEdge(n + 2 * (dep[i] + 1), i, p);
        if (dep[i] + k <= maxdep)
            addEdge(i, n + 2 * (dep[i] + k) - 1, 0);
        if (dep[i] - k >= 0)
            addEdge(i, n + 2 * (dep[i] - k + 1), 0);
    }
    scanf("%d %d", &s, &t);
    dijkstra();
    printf("%lld\n", dis[t]);
}

int main() {
    int T = 0;
    scanf("%d", &T);
    for (int cas = 1; cas <= T; ++cas)
        solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值