[省选联考 2025] 追忆
我常常追忆过去。
Solution
这是我第一道非板子的黑。
首先解决可达性问题
注意到 \(u_i < v_i\) 所以图是个 DAG。
然后就有个典的 bitset 维护可达性问题。直接设 \(f_i\) 表示 \(i\) 点可以到达的集合。
我们反着跑拓扑即可。时间复杂度 \(O(\frac{n^2}{w})\)。
其次解决查询
接下来,问题转化为求 \(\max_{i\in f_x\cap T}\{ b_i\}\) 其中 \(T=\{k | a_k\in[l,r]\}\)。
考虑如何解决对于 \(a_y\) 的限制
容易发现,符合要求的 \(a\) 都是连续的,而且信息没有可加性,所以不妨考虑进行值域上的分块。设块长为 \(B\)。
借助差分的思想,考虑对于每个块维护一个 bitset 表示 \(\{j|a_j\in[iB,n]\}\) 的集合,查询的时候只需要对于整块异或一下(后面相同的都被异或掉了),散块暴力插入即可。
这样 \(T\) 集合就被求出来了。
如何寻找最大的 \(b_k\)
记 \(S = f_x\cap T\)。
类似的,考虑对 \(b\) 同样像 \(a\) 那样在值域上维护 \(\frac{n}{B}\) 个 bitset,查询的时候我们只需要二分一个最大的 \(p\) 使得 \(p\) 之后的集合交上 \(S\) 为空。那么答案肯定在第 \(p\) 个块之中。我们只需要 \(O(B)\) 去找一下这个集合内最靠后的 \(1\) 即可。
最后解决修改
由于对 \(a\) 维护的 bitset 总共只有 \(\frac{n}{B}\) 个,所以我们可以暴力的把 \(a_x,a_y\) 从原本的 bitset 里扣掉,然后再暴力的加上。
对于 \(b\) 同理。
解决完毕
然后我们就优美的把这道题解决了。
我该在哪里停留?我问我自己。
Code
#include <bits/stdc++.h>
using namespace std;
#define fst ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N = 1e5 + 10, M = 350;
int n, m, q, B, in[N], a[N], b[N], pa[N], pb[N], id[N];
vector<int> e[N];
bitset<N> f[N];
bitset<N> fa[M], fb[M];
// 分为 4 部分
// 1: 用 bitset 维护 DAG 的可达性
// 2: 对值域分块,开 n/B 个 bitset 每个维护 a[j] \in [iB, n] 的 j 的集和 对 b 同理
// 3: 二分 p 使得 p 最大且满足 T & fb[p] 不为空 然后暴力扫 O(B) 个点
// 4: 修改直接暴力删掉原来的,加上新的
void topsort()
{
queue<int> q;
for (int i = 1; i <= n; i++) if (!in[i]) q.push(i);
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto v : e[u]) {
f[v] |= f[u];
if (!--in[v]) q.push(v);
}
}
}
void modify(int opt, int x, int y)
{
if (!opt) {
for (int i = 0; i <= a[x] / B; i++) fa[i].reset(x);
for (int i = 0; i <= a[y] / B; i++) fa[i].reset(y);
for (int i = 0; i <= a[x] / B; i++) fa[i].set(y);
for (int i = 0; i <= a[y] / B; i++) fa[i].set(x);
} else {
for (int i = 0; i <= b[x] / B; i++) fb[i].reset(x);
for (int i = 0; i <= b[y] / B; i++) fb[i].reset(y);
for (int i = 0; i <= b[x] / B; i++) fb[i].set(y);
for (int i = 0; i <= b[y] / B; i++) fb[i].set(x);
}
}
int main()
{
fst
int c, _; cin >> c >> _;
while (_--) {
cin >> n >> m >> q;
B = sqrt(n);
for (int i = 1; i <= n; i++) {
e[i].clear(); in[i] = 0;
f[i].reset(), f[i].set(i);
id[i] = i / B;
}
for (int i = 0; i <= id[n]; i++) fa[i].reset(), fb[i].reset();
for (int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
e[v].push_back(u); in[u]++;
}
topsort();
for (int i = 1; i <= n; i++) cin >> a[i], pa[a[i]] = i;
for (int i = 1; i <= n; i++) cin >> b[i], pb[b[i]] = i;
for (int i = 0; i <= id[n]; i++)
for (int j = max(1, i * B); j <= n; j++) fa[i].set(pa[j]), fb[i].set(pb[j]);
while (q--) {
int opt, x; cin >> opt >> x;
if (opt == 1) {
int y; cin >> y;
modify(0, x, y);
swap(pa[a[x]], pa[a[y]]); swap(a[x], a[y]);
} else if (opt == 2) {
int y; cin >> y;
modify(1, x, y);
swap(pb[b[x]], pb[b[y]]); swap(b[x], b[y]);
} else {
int L, R; cin >> L >> R;
bitset<N> G;
if (id[L] < id[R]) {
G = fa[id[L] + 1] ^ fa[id[R]];
for (int i = L; id[i] == id[L]; i++) G.set(pa[i]);
for (int i = R; id[i] == id[R]; i--) G.set(pa[i]);
} else for (int i = L; i <= R; i++) G.set(pa[i]);
G &= f[x];
int l = 0, r = id[n], res = -1;
while (l <= r) {
int mid = (l + r) / 2;
if ((fb[mid] & G).any()) l = (res = mid) + 1;
else r = mid - 1;
}
int ans = 0;
if (res != -1) {
G &= (fb[res] ^ fb[res + 1]);
for (int i = min((res + 1) * B - 1, n); i >= res * B; i--) if (G.test(pb[i])) { ans = i; break; }
}
cout << ans << "\n";
}
}
}
return 0;
}

浙公网安备 33010602011771号