题解:P11831 [省选联考 2025] 追忆
看游记发现很多人提到了这道题
思路
省流:将可达性改为一个点可以到达的所有 bitset 可以做到找到即 break、访问连续和只访问
首先 DAG 可达性问题显然要使用 bitset。具体的,对每个点记录
发现如果从大到小枚举 break,跑不满。但是此时
考虑将 bitset,可以只遍历到值为 unsigned long long 类型的数,可以调用 __lg(x) 得到最高位,再让 1llu<<__lg(x)。__lg() 函数的速度是非常快的。
但是此时交换
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
vector<int> e[100010];
int a[100010],b[100010];
unsigned long long bit[100010][(int)1e5/64+10];
int wz1[100010],wz2[100010];
int tot,xx[100010],yy[100010];
int pos[100010];
int main()
{
ios::sync_with_stdio(false),cin.tie(0);
int testid,t; cin>>testid>>t; while(t--)
{
cin>>n>>m>>q;
for(int i=1; i<=n; ++i) e[i].clear();
for(int i=1; i<=m; ++i)
{
int u,v; cin>>u>>v;
e[u].push_back(v);
}
for(int i=1; i<=n; ++i) cin>>a[i];
for(int i=1; i<=n; ++i) cin>>b[i],wz1[b[i]]=i,wz2[b[i]]=a[i];
for(int i=n; i>=1; --i)
{
memset(bit[i],0,sizeof(bit[i]));
bit[i][b[i]>>6]=(1llu<<(b[i]&63));
for(int j:e[i])
{
for(int k=0; k<=(n>>6); ++k) bit[i][k]|=bit[j][k];
}
}
tot=0;
for(int i=1; i<=n; ++i) pos[i]=1;
while(q--)
{
int op,x,y,l,r; cin>>op;
if(op==1)
{
cin>>x>>y;
swap(wz2[b[x]],wz2[b[y]]);
}
if(op==2)
{
cin>>x>>y;
swap(wz1[b[x]],wz1[b[y]]);
swap(wz2[b[x]],wz2[b[y]]);
xx[++tot]=b[x],yy[tot]=b[y];
swap(b[x],b[y]);
}
if(op==3)
{
cin>>x>>l>>r;
while(pos[x]<=tot)
{
int a=(bit[x][xx[pos[x]]>>6]>>(xx[pos[x]]&63)&1);
int b=(bit[x][yy[pos[x]]>>6]>>(yy[pos[x]]&63)&1);
if(a!=b)
{
if(a==0)
{
bit[x][xx[pos[x]]>>6]+=(1llu<<(xx[pos[x]]&63));
bit[x][yy[pos[x]]>>6]-=(1llu<<(yy[pos[x]]&63));
}
else
{
bit[x][xx[pos[x]]>>6]-=(1llu<<(xx[pos[x]]&63));
bit[x][yy[pos[x]]>>6]+=(1llu<<(yy[pos[x]]&63));
}
}
++pos[x];
}
bool flag=0;
for(int j=(n>>6); j>=0 && !flag; --j)
{
if(bit[x][j]==0) continue;
unsigned long long now=bit[x][j];
while(now!=0)
{
int wz=(j<<6)+__lg(now);
if(l<=wz2[wz] && wz2[wz]<=r)
{
cout<<wz<<'\n';
flag=1;
break;
}
now-=(1llu<<__lg(now));
}
}
if(!flag) cout<<0<<'\n';
}
}
}
return 0;
}