HDU - 4871 Shortest-path tree

题意:

给定一个有 n n n 个点, m m m 条边的带权无向图,先求出 1 1 1 号结点为根的最短路径树, 1 1 1 号结点在最短路图上按结点字典序最小的顺序走到其他结点。然后求恰含 k k k 个结点的最长链的长度,以及这样的恰含 k k k 个结点的最长链有几条。 ( n ≤ 3 × 1 0 4 ,   m ≤ 6 × 1 0 4 ) (n \leq 3×10^4,~m \leq 6×10^4) (n3×104, m6×104)

链接:

https://vjudge.net/problem/HDU-4871

解题思路:

最短路径树,先求最短路,然后边按结点编号升序 d f s dfs dfs 即可,然后点分求解路径问题。

参考代码:
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 3e4 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

map<int, int> mp;
map<pii, int> mp2;
vector<pii> G[maxn], P[maxn];
pii dis[maxn];
int siz[maxn], vis[maxn];
int n, m, k, tn, rmn, rt, tot, ans1;
ll ans2;

struct Dij{

    int dis[maxn];
    void dij(int s){

        priority_queue<pii, vector<pii>, greater<pii> > q;
        for(int i = 1; i <= n; ++i) dis[i] = inf;
        dis[s] = 0, q.push({dis[s], s});
        while(!q.empty()){

            int u = q.top().second, d = q.top().first; q.pop();
            if(d != dis[u]) continue;
            for(auto &e : P[u]){

                int v = e.second, w = e.first;
                if(dis[v] > dis[u] + w){

                    dis[v] = dis[u] + w;
                    q.push({dis[v], v});
                }
            }
        }
        for(int i = 1; i <= n; ++i){

            for(auto &e : P[i]) swap(e.first, e.second);
            sort(P[i].begin(), P[i].end());
            for(auto &e : P[i]) swap(e.first, e.second);
        }
        dfs(1);
    }
    void dfs(int u){

        vis[u] = 1;
        for(auto &e : P[u]){

            int v = e.second, w = e.first;
            if(vis[v] || dis[v] != dis[u] + w) continue;
            G[u].pb({w, v}), G[v].pb({w, u});
            dfs(v);
        }
    }
} dij;

void getRt(int u, int f){

    int mx = 0; siz[u] = 1;
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(v == f || vis[v]) continue;
        getRt(v, u);
        siz[u] += siz[v];
        mx = max(mx, siz[v]);
    }
    mx = max(mx, tn - siz[u]);
    if(mx < rmn) rmn = mx, rt = u;
}

void dfs(int u, int f, int cnt, int d){

    dis[++tot] = {cnt, d};
    for(auto &e : G[u]){
        
        int v = e.second, w = e.first;
        if(v == f || vis[v]) continue;
        dfs(v, u, cnt + 1, d + w);
    }
}

void cal(int u){

    mp[0] = 0;
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(vis[v]) continue;
        tot = 0;
        dfs(v, u, 1, w);
        for(int i = 1; i <= tot; ++i){

            int tmp = k - 1 - dis[i].first;
            if(mp.find(tmp) != mp.end()) ans1 = max(ans1, mp[tmp] + dis[i].second);
        }
        for(int i = 1; i <= tot; ++i){

            if(mp.find(dis[i].first) != mp.end()){

                if(mp[dis[i].first] < dis[i].second) mp[dis[i].first] = dis[i].second;
            }
            else mp[dis[i].first] = dis[i].second;
        }
    }
    mp.clear();
}

void dfz(int u){

    vis[u] = 1;
    cal(u);
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(vis[v]) continue;
        tn = siz[v], rmn = inf, getRt(v, u);
        dfz(rt);
    }
    vis[u] = 0;
}

void cal2(int u){

    mp2[{0, 0}] = 1;
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(vis[v]) continue;
        tot = 0;
        dfs(v, u, 1, w);
        for(int i = 1; i <= tot; ++i){

            pii tmp = (pii){k - 1 - dis[i].first, ans1 - dis[i].second};
            if(mp2.find(tmp) != mp2.end()) ans2 += mp2[tmp];
        }
        for(int i = 1; i <= tot; ++i){

            ++mp2[dis[i]];
        }
    }
    mp2.clear();
}

void dfz2(int u){

    vis[u] = 1;
    cal2(u);
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(vis[v]) continue;
        tn = siz[v], rmn = inf, getRt(v, u);
        dfz2(rt);
    }
    vis[u] = 0;
}

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    int t; cin >> t;
    while(t--){

        cin >> n >> m >> k;
        ans1 = 0, ans2 = 0;
        for(int i = 1; i <= n; ++i){

            P[i].clear();
            G[i].clear();
        }
        for(int i = 1; i <= m; ++i){

            int u, v, w; cin >> u >> v >> w;
            P[u].pb({w, v}), P[v].pb({w, u});
        }
        dij.dij(1);
        for(int i = 1; i <= n; ++i) vis[i] = 0;
        // for(int i = 1; i <= n; ++i) cout << sz(G[i]) << endl;
        tn = n, rmn = inf, getRt(1, 0);
        dfz(rt);
        tn = n, rmn = inf, getRt(1, 0);
        dfz2(rt);
        cout << ans1 << " " << ans2 << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值