[省选联考 2025] 追忆 题解
IvanZhang2009 · · 题解
思路可以见游记。
这是一个很暴力的考场做法,似乎没看见跟我一样的。
首先有向图可达性算是比较典的
然后这两个带修看上去都非常不容易,好像只会 ABC 性质但是又没有。考察思考的方向,注意到如果
尝试解决
这种前缀和相关的题需要注意到,如果查询的复杂度和预处理的复杂度很不平衡,可以套用一些看上去几乎无意义的分块来压缩空间(有一个较深的印象是我和 irris 的这个题的这篇题解)。注意到我们分块之后,查询的时候的单点修改的复杂度是非常小的,是小常数
不妨按
实际上这个时候写一个取出所有符合要求的点求
然后考虑如何优化
考虑为什么要我们求
这就不得不提到 WC 文艺汇演的相声(这句话也给了我相当的启发):
找一个数在有序序列中的出现位置的时候,先分块!二分它在哪个块里,然后在块里二分!就做到了
O(\log\sqrt n) !
可以想到仍然对
具体地,维护所有整块代表的 bitset 的前缀和。查询的时候在大块上查询,可以极大的削掉
建议手写 bitset,理由不知道。
考场代码:
#include<bits/stdc++.h>
#define MOD 998244353
#define int long long
#define REP(i,a,n) for(int i=(a);i<(int)(n);++i)
#define pii pair<int,int>
#define pb push_back
#define all(v) v.begin(),v.end()
#define over {cout<<x<<"\n";return;}
using namespace std;
int read(){
int res=0;char c=getchar();
while(c<48||c>57)c=getchar();
do res=(res<<1)+(res<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
return res;
}
int qpow(int a,int b,int m=MOD){
int res=1;
while(b)res=b&1? res*a%m:res,a=a*a%m,b>>=1;
return res;
}
#define ui unsigned int
int ID;
vector<int>v[100005];
int n,m,q,BL,CL;
ui C[100000][1563];
ui A[400][1563];
ui B[400][1563];
int a[100000],b[100000],ia[100000],ib[100000];
ui qr[1563];
void updA(int x,int y){
REP(i,x/BL,CL)A[i][y>>6]^=1ull<<(y&63);
}
void updB(int x,int y){
REP(i,x/BL,CL)B[i][y>>6]^=1ull<<(y&63);
}
void opA(int x){
int d=x/BL-1;
if(x>=BL){
REP(j,0,m)qr[j]^=A[d][j];
}
REP(i,x/BL*BL,x+1)qr[ia[i]>>6]^=1ull<<(ia[i]&63);
}
void Main(){
n=read();m=read();q=read();
REP(i,0,n)v[i].clear();
REP(i,0,m){
int x,y;
x=read()-1;y=read()-1;
v[x].pb(y);
}
m=(n-1)>>6;++m;
for(int i=n-1;i>=0;--i){
REP(j,i>>6,m)C[i][j]=0;
C[i][(i>>6)]=1ull<<(i&63);
for(auto j:v[i]){
REP(l,j>>6,m)C[i][l]|=C[j][l];
}
}
BL=sqrt(n*7);BL=min(BL,n);
BL=min(2000ll,n);
CL=(n-1)/BL+1;
REP(i,0,n){
a[i]=read()-1;
ia[a[i]]=i;
}
REP(i,0,n){
int d=i/BL;
if(i%BL==0){
if(i){
REP(j,0,m)A[d][j]=A[d-1][j];
}else{
REP(j,0,m)A[d][j]=0;
}
}
A[d][ia[i]>>6]|=1ull<<(ia[i]&63);
}
REP(i,0,n)b[i]=n-read(),ib[b[i]]=i;
REP(i,0,n){
int d=i/BL;
if(i%BL==0){
if(i){
REP(j,0,m)B[d][j]=B[d-1][j];
}else{
REP(j,0,m)B[d][j]=0;
}
}
B[d][ib[i]>>6]|=1ull<<(ib[i]&63);
}
REP(i,0,q){
int op,x,y,l,r;
op=read();
if(op==1){
x=read()-1;y=read()-1;
swap(a[x],a[y]);
x=a[x];y=a[y];
updA(x,ia[x]);updA(x,ia[y]);
updA(y,ia[y]);updA(y,ia[x]);
swap(ia[x],ia[y]);
}else if(op==3){
x=read()-1;l=read()-1;r=read()-1;
REP(j,0,m)qr[j]=0;
if(l)opA(l-1);
opA(r);
REP(j,0,m)qr[j]&=C[x][j];
int ans=0,fl=0;
REP(j,0,m){
if(qr[j])fl=1;
}
if(!fl){
cout<<0<<'\n';
continue;
}
int l=0,r=CL-1,res=r;
while(l<=r){
int mid=(l+r)>>1,f=0;
REP(j,0,m)if(B[mid][j]&qr[j]){f=1;break;}
if(f)res=mid,r=mid-1;
else l=mid+1;
}
for(int i=res*BL;i<n;++i){
int x=ib[i];
if(qr[x>>6]&(1ull<<(x&63))){
ans=i;
break;
}
}
cout<<n-ans<<'\n';
}else{
x=read()-1;y=read()-1;
swap(b[x],b[y]);
x=b[x];y=b[y];
updB(x,ib[x]);updB(x,ib[y]);
updB(y,ib[y]);updB(y,ib[x]);
swap(ib[x],ib[y]);
}
}
}
signed main(){
freopen("recall.in","r",stdin);
freopen("recall.out","w",stdout);
int tc=1;
ID=read();tc=read();
while(tc--)Main();
return 0;
}