P11831 [省选联考 2025] 追忆 / 定期重构

题目传送门:P11831 [省选联考 2025] 追忆

本文默认 \(n,m,q\) 同阶。

我常常追忆过去。

首先题目给定的图就是一个 dag,可以使用 \(O(\frac{n^2}{\omega})\) 处理出 \(u\) 是否能到达 \(v\)

由于 \(a\) 是一个排列,考虑按值域分块,记块长为 \(B_2\),然后我们可以预处理 \(f_{i,j}\) 表示 \(i\) 的可达点中 \(a\) 值域在块 \(j\) 的最大 \(b\)

这样我们整块直接查,散块暴力判断,静态就随便做了。

但是题目有修改操作,考虑定期重构,对 \(q\) 个询问按照 \(B_1\) 分块。

对于每个块,我们先将有修改的位置标记一下,然后没有被标记的按照静态的方法做即可。

至于修改过的,直接暴力模拟修改,然后暴力找到最优值即可。

这样的复杂度即为 \(O(\frac{n^2}{\omega}+\frac{n^3}{B_1B_2}+\frac{n^2}{B_2}+nB_1)\),在 \(B_1=B_2=n^{\frac{2}{3}}\) 时取到最优复杂度 \(O(Tn^{\frac{5}{3}}+T\frac{n^2}{\omega})\)

然后这里有个小技巧,可以存下来拓扑序,然后就不需要使用 dfs 来转移了,然后为了卡常记得开 C++17。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,B1=3500,B2=3500,BUFFER_SIZE=1<<20;
char buffer[BUFFER_SIZE],*p1=buffer,*p2=buffer;
inline char my_getchar() {
	if (p1==p2){
		p2=(p1=buffer)+fread(buffer,1,BUFFER_SIZE,stdin);
		if (p1==p2) return EOF;
	}
	return *p1++;
}
inline int read(){
	char c=my_getchar();
	int ans=0;
	while(c<48||c>57) c=my_getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=my_getchar();
	return ans;
}
bitset<N>s[N];
int a[N],b[N],c[N],vis[N],d[N];
int op[N],A[N],B[N],C[N],anss[N];
int n,m,q;
vector<int>g[N];
int f[N],tot;
void print(int x){
	if (x>9) print(x/10);
	putchar(x%10^48);
}
inline void solve(){
	n=read(),m=read(),q=read();
	for (int i=1;i<=q;i++) anss[i]=0;
	for (int i=1;i<=n;i++) g[i].clear(),d[i]=0;
	for (int i=1;i<=n;i++) s[i].reset(),s[i].set(i);
	vector<int>topsort;
	for (int i=1;i<=m;i++){
		int u=read(),v=read();
		g[u].push_back(v);
		d[v]++;
	}
	for (int i=1;i<=n;i++) a[i]=read(),c[a[i]]=i;
	for (int i=1;i<=n;i++) b[i]=read();
	queue<int>q1;
	for (int i=1;i<=n;i++) if (!d[i]) q1.push(i);
	while(!q1.empty()){
		int u=q1.front();q1.pop();
		topsort.push_back(u);
		for (auto v:g[u]) if (--d[v]==0) q1.push(v);
	}
	reverse(topsort.begin(),topsort.end());
	for (auto i:topsort) for (auto j:g[i]) s[i]|=s[j];
	for (int i=1;i<=q;i++){
		op[i]=read(),A[i]=read(),B[i]=read();
		if (op[i]==3) C[i]=read();
	}
	for (int l1=1;l1<=q;l1+=B1){
		int r1=min(q,l1+B1-1);
		vector<int>tmp;
		for (int i=1;i<=n;i++) vis[i]=0;
		for (int i=l1;i<=r1;i++) if (op[i]<=2) vis[A[i]]=vis[B[i]]=1,tmp.push_back(A[i]),tmp.push_back(B[i]);
		sort(tmp.begin(),tmp.end());
		tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
		for (int l2=1;l2<=n;l2+=B2){
			int r2=min(l2+B2-1,n);
			for (int i=1;i<=n;i++) f[i]=0;
			for (int i=l2;i<=r2;i++) if (!vis[c[i]]) f[c[i]]=b[c[i]];
			for (auto i:topsort) for (auto j:g[i]) f[i]=max(f[i],f[j]);
			for (int i=l1;i<=r1;i++) 
				if (op[i]==3&&B[i]<=l2&&r2<=C[i]) anss[i]=max(anss[i],f[A[i]]);
		}
		for (int i=l1;i<=r1;i++) if (op[i]==3){
			int l2=B[i],r2=C[i];
			if ((l2-1)/B2==(r2-1)/B2){
				for (int j=l2;j<=r2;j++) if (s[A[i]][c[j]]&&!vis[c[j]]) anss[i]=max(anss[i],b[c[j]]);
				continue;
			}
			for (int j=l2;j<=((l2-1)/B2+1)*B2;j++) if (s[A[i]][c[j]]&&!vis[c[j]]) anss[i]=max(anss[i],b[c[j]]);
			for (int j=(r2-1)/B2*B2;j<=r2;j++) if (s[A[i]][c[j]]&&!vis[c[j]]) anss[i]=max(anss[i],b[c[j]]);
		}
		for (int i=l1;i<=r1;i++){
			if (op[i]==1) swap(c[a[A[i]]],c[a[B[i]]]),swap(a[A[i]],a[B[i]]);
			if (op[i]==2) swap(b[A[i]],b[B[i]]);
			if (op[i]==3){
				int l2=B[i],r2=C[i];
				for (auto j:tmp) if (s[A[i]][j]&&l2<=a[j]&&a[j]<=r2) anss[i]=max(anss[i],b[j]);
			}
		}
	}
	for (int i=1;i<=q;i++) if (op[i]==3) print(anss[i]),putchar(10); 
}
int main(){
	read();int T=read();
	while(T--) solve();
	cerr<<(double)clock()/CLOCKS_PER_SEC;
    return 0;
}
posted @ 2026-01-09 23:54  OTn53_qwq  阅读(95)  评论(0)    收藏  举报