loj 4823 「联合省选 2025」追忆
题目传送门
solution 1
首先处理这个可达性只能通过 bitset。于是我们有一个 1G 的数组了。
然后一个容易想到的思路是,我们去维护查询 $a_i \in [l, r]$ 中的点有哪些。然后将它和后继节点的 bitset 求交,假设这个集合为 $S$。现在变成求一个 $x$ 使得满足 $b_i \geqslant x$ 那些点的集合 $T_x$ 与 $S$ 的交集非空。
由于需要支持单点修改,前缀查询,容易想到用树状数组。但是这样空间复杂度和时间复杂度都很高。问题主要出在我们并不太希望有太多的信息上传。因此我们直接考虑分块。直接对块间的每个后缀维护 bitset。假设块大小为 $B$,那么修改的时间复杂度为 $O(n/B)$,查询的复杂度为 $O(\frac{n}{\omega} +B)$
查询的时候类似,先在块间二分,然后单块的时候暴力即可。时间复杂度 $O(\frac{nq}{\omega}\log \frac{n}{B} + qB)$。$B$ 取大一些就可以在各大 OJ 上通过了。
solution 2
如果希望去掉 $\log$,那么我们需要去掉二分。那么我们需要枚举 $b$ 这一维。此时我们需要考虑哪些询问已经被满足了。但是这会带来时间轴上的问题:需要考虑不断产生的修改操作。
考虑对时间轴分块。每 $D$ 个操作分为一块。那么考虑变成了两部分:在块内受到影响的 $i$ 和未受到影响的 $i$。对于受到影响的我们直接暴力更新答案即可。这一部分总时间复杂度为 $O(qD)$。对于未受到影响的,我们要去按 $b$ 从大到小枚举 $i$,我们希望判断对于一个 $i$ 在哪些询问中是合法的。直接把这 $q$ 个询问对应的 mask 矩阵转置过来比较困难。我们考虑对两个条件分别为每个点求对应合法 $q$ 的属性。
- 对于后继限制,我们沿着拓扑序然后压位扫一遍即可,时间复杂度 $O(\frac{mD}{\omega})$。
- 对于 $a$ 在 $[l, r]$ 的限制,可以看作每个 $q$ 对区间加上 $2^{i}$。异或差分一下。总时间复杂度 $O(\frac{nD}{\omega})$
之后从大到小枚举 $b$,对于首次合法的询问记录答案即可。时间复杂度也是 $O(\frac{nD}{\omega})$。
总共有 $O(\frac{q}{D})$ 块,总时间复杂度是 $O(\frac{nq}{\omega})$。为了实现方便 $D$ 取 64 即可。
Code
写的是 solution 1
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 128;
// const int N = 1e4 + 16;
const int chunk_base = 12; // chunk_size = 2048
int T;
int n, m, q;
bitset<N> f[N];
vector<int> G[N];
class SuffixMaintainer {
public:
int cnt;
int p[N], *q; // p[a_i] = i, q = a
bitset<N> chk[(N >> chunk_base) + 2];
void build(int* a) {
q = a;
cnt = (n + (1 << chunk_base) - 1) >> chunk_base;
for (int i = 0; i < n; i++) {
p[q[i]] = i;
}
for (int i = 0; i < n; i++) {
chk[i >> chunk_base].set(p[i]);
}
for (int i = cnt - 1; ~i; i--) {
chk[i] |= chk[i + 1];
}
}
// >= l
bitset<N> query(int l) {
int cid = l >> chunk_base;
int R = min((cid + 1) << chunk_base, n);
auto res = chk[cid + 1];
for (int i = l; i < R; i++) {
res.set(p[i]);
}
return res;
}
// erase a[x] = y
void remove(int x) {
int y = q[x];
for (int i = y >> chunk_base; ~i; i--) {
chk[i].reset(x);
}
q[x] = -1;
p[y] = -1;
}
// update a[x] = y
void update(int x, int y) {
q[x] = y;
p[y] = x;
for (int i = y >> chunk_base; ~i; i--) {
chk[i].set(x);
}
}
void clear() {
for (int i = 0; i < cnt; i++) {
chk[i].reset();
}
}
};
int a[N], b[N];
SuffixMaintainer A, B;
void solve() {
scanf("%d%d%d", &n, &m, &q);
for (int i = 0, u, v; i < m; i++) {
scanf("%d%d", &u, &v);
--u, --v;
G[u].push_back(v);
}
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
--a[i];
}
for (int i = 0; i < n; i++) {
scanf("%d", b + i);
--b[i];
}
for (int i = n - 1; ~i; i--) {
f[i].set(i);
for (auto e : G[i]) {
f[i] |= f[e];
}
}
A.build(a);
B.build(b);
int op, x, l, r;
while (q--) {
scanf("%d%d%d", &op, &x, &l);
--x, --l;
if (op == 1) {
if (x == l) {
continue;
}
int vx = a[x], vy = a[l];
A.remove(x);
A.remove(l);
A.update(x, vy);
A.update(l, vx);
} else if (op == 2) {
if (x == l) {
continue;
}
int vx = b[x], vy = b[l];
B.remove(x);
B.remove(l);
B.update(x, vy);
B.update(l, vx);
} else {
scanf("%d", &r);
--r;
auto msk = f[x] & (A.query(l) ^ A.query(r + 1));
int L = 0, R = B.cnt - 1;
while (L <= R) {
int mid = (L + R) >> 1;
if ((B.chk[mid] & msk).any()) {
L = mid + 1;
} else {
R = mid - 1;
}
}
int p = min(L << chunk_base, n) - 1;
while (~p) {
if (msk.test(B.p[p])) {
break;;
}
p--;
}
printf("%d\n", p + 1);
}
}
}
void clear() {
for (int i = 0; i < n; i++) {
G[i].clear();
}
for (int i = 0; i < n; i++) {
f[i].reset();
}
A.clear();
B.clear();
}
int main() {
freopen("recall.in", "r", stdin);
freopen("recall.out", "w", stdout);
scanf("%*d%d", &T);
while (T--) {
solve();
clear();
}
return 0;
}
浙公网安备 33010602011771号