[CF1442C] Graph Transpositions

[CF1442C] Graph Transpositions - 分层图最短路

Description

给你一个(n)个顶点和(m)条边的有向图。顶点编号从(1)(n)。顶点(1)处有一个标记。

你可以进行以下两种操作:

  • 移动标记:如果存在一条(u o v)的边,将标记从(u)移动到(v),这个操作需要(1)秒。
  • 图翻转:翻转图上的所有边的方向,将图上每一条边(u o v)替换为(v o u),第(k)次使用这个操作需要耗时(2^{k-1})秒。

你需要找到将标记从(1)移动到(n)的最短时间,请将答案对(998,244,353)取模。

Solution

朴素分层图有 (O(n^2)) 个点,需另辟蹊径

(C=lceil log_2 n ceil),则当 (k ge C) 时,层数最小不会使得答案更劣

(kle C) 的部分建分层图跑最短路

层内连边 (p o q (cost=1)),第 (k) 层到第 (k+1)(i_k o i_{k+1} (cost = 2^k))

如果无解,说明 (k>C),此时我们优先最小化层数

每次做完层内转移,然后集体转移到下一层

(k mod 2=0) 则用正图,否则用反图

先在层内转移,内连边 (p o q (cost=1))

后再层间转移,只要 (n) 点还未到达,所有点就一起转移,从 (k) 层到 (k+1) 层,整体加上代价 (2^k)

这个代价额外存一个偏移量中即可,(f[]) 中记录的代价只是 (k le C) 部分的代价和 (k >C) 部分的层内转移代价,这样 (f[]) 中的数字不用取模,可以比较大小

由于边权只有 (0/1),总体的时间复杂度还是 (O(m log n))

最短路过程中记录代价用二维数组 (dis[][]),后续过程用 (f[])

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int mod = 998244353;
const int N = 400005;
const int M = 25;

int qpow(int p, int q)
{
    return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
}

int n, m;
int dis[M][N], f[N];
bool vis[M][N];
vector<int> g[2][N];

void spfa()
{
    queue<pair<int, int>> que;
    dis[0][1] = 0;
    que.push({0, 1});
    vis[0][1] = 1;
    while (que.size())
    {
        auto [k, p] = que.front();
        que.pop();
        for (int q : g[k & 1][p])
        {
            if (dis[k][q] > dis[k][p] + 1)
            {
                dis[k][q] = dis[k][p] + 1;
                if (vis[k][q] == 0)
                    que.push({k, q}), vis[k][q] = 1;
            }
        }
        if (k < 18)
            if (dis[k + 1][p] > dis[k][p] + (1ll << k))
            {
                dis[k + 1][p] = dis[k][p] + (1ll << k);
                if (vis[k + 1][p] == 0)
                    que.push({k + 1, p}), vis[k + 1][p] = 1;
            }
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int t1, t2;
        cin >> t1 >> t2;
        g[0][t1].push_back(t2);
        g[1][t2].push_back(t1);
    }
    memset(dis, 0x3f, sizeof dis);
    memset(f, 0x3f, sizeof f);
    spfa();
    int ans = 1e18;
    for (int i = 0; i < 18; i++)
        ans = min(ans, dis[i][n]);
    if (ans < 1e9)
    {
        cout << ans << endl;
    }
    else
    {
        f[1] = 0;
        queue<int> que, que_next;
        que.push(1);
        que_next.push(1);
        int delta = 0;
        for (int k = 0;; k++)
        {
            while (que.size())
            {
                int p = que.front();
                que.pop();
                for (int q : g[k & 1][p])
                {
                    if (f[q] > f[p] + 1)
                    {
                        f[q] = f[p] + 1;
                        que.push(q);
                        que_next.push(q);
                    }
                }
            }
            while (que_next.size())
            {
                que.push(que_next.front());
                que_next.pop();
            }
            if (f[n] < 1e9)
            {
                cout << (f[n] + delta) % mod << endl;
                return 0;
            }
            delta += qpow(2, k);
            delta %= mod;
        }
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14560282.html