[省选联考 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;
}
posted @ 2025-05-15 21:37  Dtwww  阅读(31)  评论(0)    收藏  举报