题解:P11831 [省选联考 2025] 追忆

· · 题解

首先谴责一下这个民间数据啊,O(nq) 给我跑了 76pts。然后块长调错复杂度烂完给过了。

考虑分块。每个块维护这个块及以后所有点的 bitset,即 $f_{[l,r]}$ 是所有满足 $a_i\ge l$ 的 $i$ 构成的 bitset。内部则维护块内点的后缀并。 对于修改操作,由于 $a$ 是排列,直接暴力修改即可做到 $O(\sqrt{n})$。查询操作是直接合并整块的 bitset 并插入散块,是 $O(\frac{n}{w}+\sqrt{n})$ 的。 这个部分的时间复杂度是 $O(q(\sqrt{n}+\frac{n}{w}))$。 那么现在,我们就可以求出每个查询的有效点集合了。现在的问题是怎样求其中的 $\max b$。 对于 $b$ 我们类似的分块,$g_{[l,r]}$ 是所有满足 $b_i\ge l$ 的 $i$ 构成的 bitset。查询的求最大的 $x$ 使得 $b_i \ge x$ 的 $i$ 构成的 bitset 与有效点有交。$O(\frac{n\sqrt{n}}{w})$。 注意到我们散块和整块的复杂度极度不平衡,仔细分析一下: * 对于整块,复杂度 $O(\frac{n^2}{Bw})$。修改复杂度为 $O(\frac{n}{B})$。 * 对于散块,修改和查询都是 $O(B)$。 取 $B=10000$,随便跑啊。 [AC Link.](https://www.luogu.com.cn/record/205805945) 更新:官方数据不是出来了吗,太恐怖了,给我原来的代码干 T 了,加一点小卡常就好了(甚至可以说是一些常识?) 1. 去掉 `#define int long long`。 2. `#define endl '\n'`。 [AC Link.](https://www.luogu.com.cn/record/206222406) 也就 2k 出头,不长的。 update:感谢@[hepp](https://www.luogu.com.cn/user/541313) 指出了原题解的错误。在上面的代码中我使用 `.size()` 来判断这个 `bitset` 里是否有 1,但是事实上 `.size()` 返回的是大小而非 1 的个数。导致复杂度退化。但是这玩意能给过了也是神了。应当改为 `.count()` 或 `.any()`。 [新的提交记录](https://www.luogu.com.cn/record/235043893)。 新的代码: ```cpp #include<bits/stdc++.h> // #define int long long #define endl '\n' using namespace std; const int mod=998244353,inf=0x3f3f3f3f3f3f3f3f; const int N=1e5+10,M=2e5+10; bitset<N>to[N]; vector<int>e[N]; int n,m,q; const int B1=400,B2=10000; bitset<N>f[N/B1+10]; bitset<N>g[N/B2+10]; int fid[N],gid[N]; int a[N],b[N],br[N],ar[N]; void solve() { cin >> n >> m >> q; for ( int i = 1 ; i <= n ; i++ ) e[i].clear(),to[i]=0; for ( int i = 1 ; i <= n ; i++ ) to[i][i]=1; while(m--) { int u,v;cin >> u >> v; e[u].push_back(v); } for ( int i = 1 ; i <= n ; i++ ){ cin >> a[i];ar[a[i]]=i; } for ( int i = 1 ; i <= n ; i++ ){ cin >> b[i];br[b[i]]=i; } for ( int i = n ; i >= 1 ; i-- ) for ( auto v:e[i] )to[i]|=to[v]; for ( int i = 1 ; i <= n+1 ; i++ ) fid[i]=(i+B1-1)/B1, gid[i]=(i+B2-1)/B2; for ( int i = 1 ; i <= fid[n]+1 ; i++ )f[i]=0; for ( int i = 1 ; i <= gid[n]+1 ; i++ )g[i]=0; for ( int i = 1 ; i <= n ; i++ ) f[fid[a[i]]][i]=1, g[gid[b[i]]][i]=1; for ( int i = fid[n]-1 ; i >= 1 ; i-- ) f[i]|=f[i+1]; for ( int i = gid[n]-1 ; i >= 1 ; i-- ) g[i]|=g[i+1]; while(q--) { int op,x,y,l,r; cin >> op; if(op==1) { cin >> x >> y; for ( int i = 1 ; i <= fid[a[x]] ; i++ )f[i][x]=0; for ( int i = 1 ; i <= fid[a[y]] ; i++ )f[i][x]=1; for ( int i = 1 ; i <= fid[a[y]] ; i++ )f[i][y]=0; for ( int i = 1 ; i <= fid[a[x]] ; i++ )f[i][y]=1; swap(a[x],a[y]); swap(ar[a[x]],ar[a[y]]); }else if(op==2){ cin >> x >> y; for ( int i = 1 ; i <= gid[b[x]] ; i++ )g[i][x]=0; for ( int i = 1 ; i <= gid[b[y]] ; i++ )g[i][x]=1; for ( int i = 1 ; i <= gid[b[y]] ; i++ )g[i][y]=0; for ( int i = 1 ; i <= gid[b[x]] ; i++ )g[i][y]=1; swap(b[x],b[y]); swap(br[b[x]],br[b[y]]); }else{ cin >> x >> l >> r; bitset<N>toa;toa=0; toa=f[fid[l]+1]; for ( int i = l ; i <= min(n,fid[l]*B1) ; i++ ) toa[ar[i]]=1; toa^=f[fid[r+1]+1]; for ( int i = r+1 ; i <= min(n,fid[r+1]*B1) ; i++ ) toa[ar[i]]=1-toa[ar[i]]; toa&=to[x]; int flg=0; for ( int i = gid[n] ; i >= 1 ; i-- ) { if((g[i]&toa).any()) { for ( int j = min(n,i*B2) ; j >= (i-1)*B2+1 ; j-- ) if(toa[br[j]]) { flg=1; cout << j << endl; break; } } if(flg)break; } if(!flg)cout << 0 << endl; } } } signed main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int c,T;cin >> c >> T; while(T--)solve(); return 0; } ```