2025.3.23 鲜花

[省选联考 2025] 追忆 题解

hello (bpm) 2025

恭喜获得 最速被击破奖🏆

不会 bitset,赛时想不到分块也是没救了。

首先必然要坚定 bitset 信念,因为其严格难于导出子图。

维护后继直接 bitset 就是 \(\frac{nm}w\) 的。

考虑到第二个限制 \(l, r\) 如何维护,容易想到的暴力是开 \(n\) 个 bitset,维护出 \(k \in [1, n]\) 的所有集合 \(A_k = \{i \mid a_i \ge k\}\),但是首先空间开不下,其次还有修改。

于是乎想到分块, 设块长是 \(B\),则只维护 \(k = xB\),这样修改是 \(\frac nB\) 的,查询是 \(B\) 的,平衡得 \(\sqrt n\)

这样我们就得到了限制集合 \(C\)

考虑如何求出最大的 \(b\),依然类似维护出 \(B_k\),其等价于是最大的一个 \(k\),满足 \(B_k \cap C \not = \varnothing \And B_{k + 1} \cap C = \varnothing\),依然类似的分块,如果暴力二分复杂度是 \(\frac{n\log \sqrt n}w + \sqrt n\) 的,好像能过 88pts。

考虑优化,容易发现前面的集合对后面有偏序关系,所以这是一个类似前缀和上二分的形式,考虑双指针,手写 bitset,将判断拆成 \(\frac nw\) 个 ull 判交,于是我们枚举每个 ull,维护一个 \(p\) 表示当前的 \(k\),每次尝试更新 \(k \gets k + 1\),最后的 \(p\) 显然就是 \(k\)

最终复杂度 \(\mathcal O(\frac{(n + m)q}w + q\sqrt n)\)

Code
/* Local File
in_out/in.in
in_out/out.out
*/
#include <bits/stdc++.h>
using namespace std;
using llt = long long;
using ull = unsigned long long;
using llf = long double;
#define endl '\n'
 
const int N = 1e5 + 3, W = 64, D = N / W + 1, B = 600, S = N / B + 3;
int n, m, q, va[N], vb[N], pa[N], pb[N];

class Bset{
private:
	ull o[D];
public:
	bool operator[](int p) const{
		int l = p / W, r = p - l * W;
		return (o[l] >> r) & 1;
	}
	ull &operator()(int p){
		return o[p]; 
	}
	void Set(int p){
		int l = p >> 6, r = p - l * W;
		o[l] = o[l] | (1ull << r);
	}
	void Res(int p){
		int l = p >> 6, r = p - l * W;
		o[l] = o[l] & ~(1ull << r);
	}
	Bset &operator|=(const Bset &_){
		for(int i = 0; i < D; ++i)
			o[i] |= _.o[i];
		return *this;
	}
	Bset operator|(const Bset &_) const{
		Bset r(*this);
		return r |= _;
	}
	Bset &operator^=(const Bset &_){
		for(int i = 0; i < D; ++i)
			o[i] ^= _.o[i];
		return *this;
	}
	Bset operator^(const Bset &_) const{
		Bset r(*this);
		return r ^= _;
	}
	Bset &operator&=(const Bset &_){
		for(int i = 0; i < D; ++i)
			o[i] &= _.o[i];
		return *this;
	}
	Bset operator&(const Bset &_) const{
		Bset r(*this);
		return r &= _;
	}
};

Bset sn[N], ca[S], cb[S];
int bln, id[N], bl[N], br[N];

struct Gph{
	vector<int> to[N];
	void Add(int u, int v){
		to[u].emplace_back(v);
	}
	void ADD(int u, int v){
		Add(u, v), Add(v, u);
	}
	void Clr(){
		for(int i = 1; i <= n; ++i)
			to[i].clear();
	}
#define For_to(u, v, g) for(auto v : g.to[u])
} g, rg;

int rd[N];
void Solve(){
	cin >> n >> m >> q;
	for(int i = 1; i <= m; ++i){
		int u, v; cin >> u >> v;
		g.Add(u, v), ++rd[u], rg.Add(v, u);
	}
	for(int i = 1; i <= n; ++i)
		cin >> va[i], pa[va[i]] = i;
	for(int i = 1; i <= n; ++i)
		cin >> vb[i], pb[vb[i]] = i;
	queue<int> que;
	for(int i = 1; i <= n; ++i) if(!rd[i])
		que.emplace(i);
	while(!que.empty()){
		int u = que.front(); que.pop();
		sn[u].Set(u);
		For_to(u, v, g) sn[u] |= sn[v];
		For_to(u, v, rg)
			if(!--rd[v]) que.emplace(v);
	}
	bln = 0;
	for(int l = 1; l <= n; l += B){
		++bln;
		for(int j = bl[bln] = l, r = br[bln] = min(l + B - 1, n); j <= r; ++j)
			ca[bln].Set(pa[j]), cb[bln].Set(pb[j]), id[j] = bln;
	}
	for(int i = bln - 1; i; --i)
		ca[i] |= ca[i + 1], cb[i] |= cb[i + 1];
	for(int tst = 1; tst <= q; ++tst){
		int op; cin >> op;
		if(op == 1){
			int x, y; cin >> x >> y;
			int ix = id[va[x]], iy = id[va[y]];
			swap(va[x], va[y]), pa[va[x]] = x, pa[va[y]] = y;
			for(int i = 1; i <= ix; ++i) ca[i].Res(x);
			for(int i = 1; i <= iy; ++i) ca[i].Set(x);
			for(int i = 1; i <= iy; ++i) ca[i].Res(y);
			for(int i = 1; i <= ix; ++i) ca[i].Set(y);
		}else if(op == 2){
			int x, y; cin >> x >> y;
			int ix = id[vb[x]], iy = id[vb[y]];
			swap(vb[x], vb[y]), pb[vb[x]] = x, pb[vb[y]] = y;
			for(int i = 1; i <= ix; ++i) cb[i].Res(x);
			for(int i = 1; i <= iy; ++i) cb[i].Set(x);
			for(int i = 1; i <= iy; ++i) cb[i].Res(y);
			for(int i = 1; i <= ix; ++i) cb[i].Set(y);
		}else{
			int u, l, r; cin >> u >> l >> r;
			int il = id[l], ir = id[r];
			Bset k(ca[il] ^ ca[ir]);
			for(int i = bl[ir]; i <= r; ++i) k.Set(pa[i]);
			for(int i = bl[il]; i < l; ++i) k.Res(pa[i]);
			k &= sn[u];
			int p = 0;
			for(int i = 0; i < D; ++i)
				while(p < bln && (cb[p + 1](i) & k(i))) ++p;
			if(!p) cout << 0 << endl;
			else
				for(int i = br[p]; i >= bl[p]; --i){
					int p = pb[i];
					if(k[p]){
						cout << i << endl;
						break;
					}
				}
		}
	}
}

void Clear(){
	memset(sn, 0, sizeof sn);
	memset(ca, 0, sizeof ca);
	memset(cb, 0, sizeof cb);
	g.Clr(), rg.Clr();
}

int main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int c, t; cin >> c >> t;
	while(t--) Solve(), Clear();
}
P

posted @ 2025-03-23 09:53  xrlong  阅读(44)  评论(2)    收藏  举报

Loading