P9150 邮箱题 题解
P9150 邮箱题 题解
注意到 \(n^2\) 的做法给了足足 70pts,那让我们先来考虑如何 \(n^2\) 解决这个问题。
这样一来我们可以暴力枚举每个点走动的过程。由于 \(k\) 是一个排列,换句话说当你踏入一个点时你下一个要去的点已经确定了。现在要研究的是如何判定能否到达那个点。设当前的点为 \(x\),你要去的点为 \(k_x\),那么要走到 \(k_x\) 意味着你首先只能走已走过的点,换句话说你要维护一个路径上经过的点组成的一个个强连通分量,检查 \(x\) 所在强连通分量有没有终点为 \(k_x\) 的边,有的话就合法,然后更新合并强连通分量。
对于 \(O(n)\) 的做法,一个个算显得不太现实,考虑如何均摊。注意到我们每次维护的实际上是 \(k\) 形成的排列一次次循环的过程,实际上有很多冗余,那么不妨把 \(k\) 排列中一个个轮换环提出来,对每一个环分别维护。
那么对每个环断环成链复制一下来维护,从后往前倒序遍历每个点来维护其之后通达性情况。加入一个点后,我们需要先维护这个点能否与上一个点所在的强连通分量有连边,以此检查能否通达。为了回答第一问,我们还需要维护每个点最右能走到的位置,我们称之为区间,维护区间最右端即可。之后我们需要用一些指针维护边来合并相邻的连通块与区间,这样就做完了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 5;
int n, m;
int k[N];
vector<int>v[N];
struct BCJ {
int fa[N];
int fnd(int x) {
return x == fa[x] ? x : fa[x] = fnd(fa[x]);
}
void mge(int x, int y) {
x = fnd(x), y = fnd(y);
fa[x] = y;
}
} P, Q;
int p[N], q[N];
bool vis[N];
int stk[N], top;
int num[N];
int ans1[N], ans2[N];
void sve(int w) {
while (!vis[w]) {
vis[w] = 1;
stk[++top] = w;
num[w] = top;
w = k[w];
}
for (int i = top * 2; i; --i) {
P.fa[i] = Q.fa[i] = i;
p[i] = q[i] = 0;
int x = stk[(i - 1) % top + 1];
for (int y : v[x]) {
if (!num[y]) continue;
y = num[y];
if (y + top < i) y += top;
if (y > i) y -= top;
q[i] = max(q[i], y);
if (y < i) y += top;
if (y <= top * 2) p[Q.fnd(y)] = max(p[Q.fnd(y)], P.fnd(y));
}
while (1) {
while (1) {
int x = P.fnd(i), y = Q.fnd(i);
if (x < p[y]) P.mge(x, x + 1);
else break;
}
int x = P.fnd(i), y = Q.fnd(i);
p[y] = 0;
if (x != y || q[y + 1] < i || y == 2 * top) break;
Q.mge(y, y + 1);
}
ans1[x] = min(Q.fnd(i) - i + 1, top), ans2[x] = min(P.fnd(i) - i + 1, top);
}
for (int i = 1; i <= top; i++) num[stk[i]] = 0, stk[i] = 0;
top = 0;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> k[i];
while (m--) {
int x, y;
cin >> x >> y;
v[y].push_back(x);
}
for (int i = 1; i <= n; i++)
if (!vis[i]) sve(i);
for (int i = 1; i <= n; i++) cout << ans1[i] << ' ' << ans2[i] << '\n', v[i].clear(), vis[i] = 0;
}
return 0;
}

浙公网安备 33010602011771号