「省选联考2025-追忆」题解

P11831 [省选联考 2025] 追忆

pref

我常常追忆过去。

恍若昨日,却已近半年。

不再的旧日,不再的旧友。

真实的泡沫在伸手触碰的瞬间便化作虚无,连流光的幻影也不曾留下。

旧时放飞的梦想,越来越近,亦或是越来越远了。

我该在哪里停留?我问我自己。

sol

考虑分开处理连通性限制与 \(a\) 的限制。

先考虑连通性限制,这个拓扑加 bitset 处理即可,本题的图比较特殊,倒序遍历极为拓扑序。复杂度 \(O(\frac{nm}{w})\)

考虑对 \(a\) 的限制,考虑分块,令块长为 \(S=\sqrt n\),对每个块开一个 bitset,第 \(x\) 块存储 \(\left\{i\mid a_i>(x-1)S\right\}\),也就是 \(a\) 值在块内的所有下标集合意义上的后缀和。

这样我们可以通过差分找出 \(\left\{i\mid a_i\in\left[l,r\right]\right\}\)。对于 \(l,r\) 同块的暴力修改即可,不同块的先差分整块,再暴力更新散块。单次复杂度是 \(O(\sqrt n+\frac{n}{w})\) 的。

\(a\) 的修改是简单的,\(O(\sqrt n)\) 暴力改 bitset 即可。

于是我们就找出了满足条件的下标,考虑如何找出这些下标内最大的 \(b\) 值。

考虑到 \(b\) 带修,我们考虑采取与 \(a\) 相同的分块方式维护。那么每次我们都只需要找到最大的与限制集合有交的块,在块内暴力跑即可。直接找是 \(O(\frac{n\sqrt n}{w})\) 的,不太优,考虑手写 bitset,然后逐个 ull 更新答案。这样答案最多被更新 \(\frac{n}{S}=\sqrt n\) 次,且 ull 的按位与操作是 \(O(1)\) 的。

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

code

const int N=1e5+5,W=1570,w=64,S=320;

struct btst{
	ull val[W];
	inline void reset(){memset(val,0,sizeof val);}
	inline void set(const int &x){val[x>>6]|=1ull<<(x&w-1);}
	inline void flip(const int &x){val[x>>6]^=1ull<<(x&w-1);}
	inline int any(const int &x){return val[x>>6]>>(x&w-1)&1;}
	inline void operator&=(const btst &b){repl(i,0,W)val[i]&=b.val[i];}
	inline void operator|=(const btst &b){repl(i,0,W)val[i]|=b.val[i];}
	inline void operator^=(const btst &b){repl(i,0,W)val[i]^=b.val[i];}
};

int n,m,q,nn;
int a[N],b[N];
int ta[N],tb[N];
vec<int> G[N];

btst T[N],A[S],B[S],C;

inline void Main(){
	read(n,m,q);
	nn=(n+S-1)/S;
	rep(i,1,nn)A[i].reset(),B[i].reset();
	rep(i,1,n)G[i].clear(),T[i].reset();
	rep(i,1,m){
		int u,v;read(u,v);
		G[u].pub(v);
	}
	per(i,n,1){
		T[i].set(i);
		for(auto j:G[i])T[i]|=T[j];
	}
	rep(i,1,n){
		read(a[i]);ta[a[i]]=i;
		per(j,(a[i]+S-1)/S,1)A[j].set(i);
	}
	rep(i,1,n){
		read(b[i]);tb[b[i]]=i;
		per(j,(b[i]+S-1)/S,1)B[j].set(i);
	}
	while(q--){
		int o;read(o);
		if(o==1){
			int x,y;
			read(x,y);
			if(a[x]>a[y])swap(x,y);
			int L=(a[x]+S-1)/S,R=(a[y]+S-1)/S;
			rep(j,L+1,R)A[j].flip(x),A[j].flip(y);
			swap(a[x],a[y]);swap(ta[a[x]],ta[a[y]]);
		}else if(o==2){
			int x,y;
			read(x,y);
			if(b[x]>b[y])swap(x,y);
			int L=(b[x]+S-1)/S,R=(b[y]+S-1)/S;
			rep(j,L+1,R)B[j].flip(x),B[j].flip(y);
			swap(b[x],b[y]);swap(tb[b[x]],tb[b[y]]);
		}else{
			int x,l,r;
			read(x,l,r);C.reset();
			int L=(l+S-1)/S,R=(r+S-1)/S;
			if(L==R){
				rep(i,l,r)C.set(ta[i]);
			}else{
				C=A[L+1];C^=A[R];
				rep(i,l,L*S)C.set(ta[i]);
				rep(i,(R-1)*S+1,r)C.set(ta[i]);
			}
			C&=T[x];
			int p=0;
			repl(i,0,W)while(p+1<=nn&&C.val[i]&B[p+1].val[i])++p;
			if(!p)put(0);
			else{
				l=(p-1)*S+1;
				r=min(p*S,n);
				int ans=0;
				rep(i,l,r)if(C.any(tb[i]))ans=i;
				put(ans);
			}
		}
	}
}

aft

虽然说也有些小细节不是特别无脑吧,但整体来看确实是道相对简单的分块了。

曾经的日子无法重来,我只不过是一个过客。但我仍然渴望在每一次追忆之旅中留下闲暇时间,在一个场景前驻足,在岁月的朦胧里瞭望过去的自己,感受尽可能多的甜蜜。美好的时光曾流过我的身体,我便心满意足。

posted @ 2025-07-01 22:09  LastKismet  阅读(78)  评论(0)    收藏  举报