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;
}

浙公网安备 33010602011771号