2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset

Posted kaka0010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset相关的知识,希望对你有一定的参考价值。

原题链接:https://ac.nowcoder.com/acm/contest/11258/J

题意

正确的弗洛伊德算法是依照枚举k, i, j的顺序,k是转移的中间点,i是出发点,j是到达点。现在按照i,j,k的枚举顺序,问有多少点对之间的最短路仍然是正确的。

分析

我们分两种情况来考虑

  1. u本来就不能到达v,u和v是同一个点。
  2. u通过最短路径dis[u,k]到达k,再通过最短路经dis[k,v]到达v,且k是u,v最短路径上的必经点

对于第一种情况我们直接统计就可以了,对于第二种,我们需要预处理出所有点作为出发点的最短路。然后再按照题目中的枚举顺序去枚举。比如我们枚举从u出发到所有点的距离,存在dis[v]中,那么我们需要同时满足存在点p,dis[u][p]和dis[p][v]都是最短路,且p位于u,v的最短路径上。如果直接暴力算是O(N^3)的,我们可以把所有经过的点用bitset压位处理。还有一处重要的剪枝,就是只有最短路才能更新最短路,因此我们将从当前u出发且满足最短路的边拎出来,用拓扑乱搞更新一下就可以。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;

#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\\n'

int can[2005][2005];
int dis[2005], vis[2005], n, m, in[2005];
vector<int> G[2005];
vector<PII> g[2005];
bitset<2005> mk[2005], f[2005], fT[2005];
struct Edge {int u, v, w;} e[5005];
struct node {
    int d, now;
    bool operator < (const node &rhs) const {
        return d > rhs.d;
    }
};
void dij(int x) {
    memset(vis, 0, sizeof vis);
    memset(dis, 0x3f, sizeof dis);
    dis[x] = 0;
    priority_queue<node> que;
    que.push({0, x});
    while (que.size()) {
        int now = que.top().now;
        que.pop();
        if (vis[now]) continue;
        vis[now] = 1;
        for (auto it : g[now]) {
            int v = it.fi;
            int w = it.se;
            if (dis[v] > dis[now] + w) {
                dis[v] = dis[now] + w;
                if (!vis[v]) {
                    que.push({dis[v], v});
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) can[x][i] = dis[i];
}
inline void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) f[i][i] = fT[i][i] = 1;
    for (int i = 1; i <= m; i++) {
        int u, v, w; cin >> u >> v >> w;
        e[i] = {u, v, w};
        g[u].push_back({v, w});
    }
    for (int i = 1; i <= n; i++) dij(i);
    for (int i = 1; i <= m; i++) {
        if (can[e[i].u][e[i].v] == e[i].w) f[e[i].u][e[i].v] = fT[e[i].v][e[i].u] = 1;
    }
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            in[j] = 0;
            mk[j].reset();
            G[j].clear();
            ans += (can[i][j] == inf);
        }
        queue<int> q;
        for (int j = 1; j <= m; j++) {
            if (can[i][e[j].u] + e[j].w == can[i][e[j].v]) {
                G[e[j].u].push_back(e[j].v);
                in[e[j].v]++;
            }
        }
        q.push(i);
        while (q.size()) {
            int now = q.front();
            q.pop();
            mk[now][now] = 1;
            for (auto v : G[now]) {
                mk[v] |= mk[now];
                if (--in[v] == 0) q.push(v);
            }
        }
        for (int j = 1; j <= n; j++) {
            if ((f[i] & mk[j] & fT[j]).count()) f[i][j] = fT[j][i] = 1;
        }
    }
    for (int i = 1; i <= n; i++) ans += f[i].count();
    cout << ans << endl;
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}

以上是关于2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)

2021牛客暑期多校训练营7xay loves trees(dfs序,维护根出发的链)

2021牛客暑期多校训练营 J. Product of GCDs 不动脑子的莫比乌斯反演做法(

2021牛客暑期多校训练营7,签到题FHI

2021牛客暑期多校训练营7 部分题题解

2021牛客暑期多校训练营2