题解:P11369 [Ynoi2024] 弥留之国的爱丽丝

\(\text{Link}\)

题意

给你 \(n\) 个结点和 \(m\) 条有向边。每条边的颜色为黑白二色之一,初始所有边都是黑色的。

你需要进行如下两种操作共 \(q\) 次操作:

  • 1 k,表示将第 \(k\) 条边的颜色进行反转。
  • 2 u v,表示询问是否能从 \(u\) 只经过黑色的边走到 \(v\)

\(n\le 5\times 10^4\)\(m,q\le 10^5\)

题解

首先问题肯定不弱于 DAG 可达性问题,所以我们只需要考虑除以 \(\omega\) 的算法。

\(b\) 进行时间分块,取出这 \(b\) 次操作中的关键点与关键边。先使用所有黑色的非关键边进行缩点,并预处理两两关键点之间能否通过这些边到达,使用 bitset,只需维护每个点能否到达每个关键点,时间复杂度 \(O(\dfrac{q}{b}\cdot (n+m)\cdot\dfrac{b+\omega}{\omega})\)

询问时使用 bitset 优化 BFS 即可,时间复杂度 \(O(q\cdot\dfrac{b^2}{\omega})\)

\(b=(n+m)^{1/3}\omega^{1/3}\),得到时间复杂度 \(O(\dfrac{q(n+m)+q(n+m)^{2/3}\omega^{2/3}}{\omega})\)

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
	
}
#define pii pair<int,int>
#define mpr make_pair
#define fir first
#define sec second
//b=[(n+m)*w]^{1/3}
//O(q*(n+m)*w^{-1}+q*(n+m)^{2/3}*w^{-1/3})
const int N=5e4+10,M=1e5+10,B=220,C=B*2+10;
int n,m,q,u[M],v[M];
bool ans[M];
struct Query{
	int op,u,v;
}qr[M]; 
vector<int>a[N],b[N];
int tim,dfn[N],low[N],bel[N],stk[N],top,blk;
bool inc[N],col[M],inb[M];
inline void Tarjan(int x){
	dfn[x]=low[x]=++tim,inc[x]=1,stk[++top]=x;
	for(auto t:a[x]){
		if(!dfn[t]) Tarjan(t),low[x]=min(low[x],low[t]);
		else if(inc[t]) low[x]=min(low[x],low[t]);
	}
	if(dfn[x]==low[x]){
		++blk;
		while(1){
			int p=stk[top--];
			inc[p]=0,bel[p]=blk;
			if(p==x) break;
		}
	}
} 
inline void init(){
	for(int i=1;i<=n;i++)
		dfn[i]=bel[i]=inc[i]=0,
		a[i].clear(),b[i].clear();
	top=tim=blk=0;
	for(int i=1;i<=m;i++)
		if(col[i]&&!inb[i])
			a[u[i]].push_back(v[i]);
}
inline void build(){
	init();
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			Tarjan(i);
}
int id[C],c,rd[N];
bitset<C>f[N],pt[C],r[C],vis,cur;
inline bool query(int u,int v){
	vis.reset(),cur.reset();
	cur[u]=1;
	for(;!cur[v];){
		int p=(cur&~vis)._Find_first();
		if(p==cur.size()) return 0;
		vis[p]=1,cur=cur|pt[p]|r[p];
	}
	return 1;
}
inline void solve(int L,int R){
	c=0;
	for(int i=1;i<=n;i++)
		rd[i]=0,f[i].reset();
	for(int i=1;i<=m;i++)
		inb[i]=0;
	vector<int>p;
	for(int i=L;i<=R;i++){
		int u=qr[i].u,v=qr[i].v;
		if(qr[i].op==1) p.push_back(::u[u]),p.push_back(::v[u]),inb[u]=1;
		else p.push_back(u),p.push_back(v);
	}
	for(int i:p)
		if(!rd[i])
			rd[i]=++c,id[c]=i; 
	build();
	for(int i=1;i<=c;i++)
		f[bel[id[i]]][i]=1;
	for(int i=1;i<=m;i++)
		if(col[i]&&!inb[i])
			b[bel[u[i]]].push_back(bel[v[i]]);
	for(int i=1;i<=blk;i++)
		for(auto j:b[i])
			f[i]|=f[j];
	for(int i=1;i<=c;i++)
		pt[i].reset(),r[i].reset();
	for(int i=1;i<=c;i++)
		for(int j=1;j<=c;j++)
			pt[i][j]=f[bel[id[i]]][j];
	for(int i=1;i<=m;i++)
		if(col[i]&&inb[i])
			r[rd[u[i]]][rd[v[i]]]=1;
	for(int i=L;i<=R;i++){
		int op=qr[i].op;
		if(op==1){
			int id=qr[i].u;
			col[id]^=1;
			if(col[id]) r[rd[u[id]]][rd[v[id]]]=1;
			else r[rd[u[id]]][rd[v[id]]]=0;
		}else{
			int u=qr[i].u,v=qr[i].v;
			ans[i]=query(rd[u],rd[v]);
		}
	}
}
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=m;i++)
		u[i]=read(),v[i]=read(),col[i]=1;
	for(int i=1;i<=q;i++){
		int op=read(),u=read(),v=0;
		if(op==2) v=read();
		qr[i]={op,u,v};
	}
	for(int i=1;i<=q;i+=B)
		solve(i,min(i+B-1,q));
	for(int i=1;i<=q;i++)
		if(qr[i].op==2)
			puts(ans[i]?"YES":"NO");
	flush();
}
posted @ 2025-05-28 11:43  ffffyc  阅读(25)  评论(0)    收藏  举报