P11369 [Ynoi2024] 弥留之国的爱丽丝 / 定期重构

题目传送门:P11369 [Ynoi2024] 弥留之国的爱丽丝

假设 \(n,m,q\) 同阶。

首先这个不弱于 DAG 联通性,考虑使用 \(\frac{1}{\omega}\) 做法。

首先我们将操作按照 \(B\) 分块,对于每一块,定义关键点为操作和询问涉及的点,关键边为操作涉及的边,那么显然关键点边个数均为 \(O(B)\) 量级。

考虑建出一个图 \(G_1\) 包含所有点和非关键且黑色的边,那么就可以直接缩点利用 bitset 维护出连通性。

然后建出一个图 \(G_2\) 包含所有关键点,如果关键点在 \(G_1\) 联通,那么这里连一条边,直接利用 bitset 存邻接矩阵。

然后建出一个图 \(G_3\) 动态维护所有关键边的状态,黑色在图中,白色不在图中,也可以利用 bitset 存,注意这里维护需要考虑一下重边。

然后依次处理所有询问,动态维护 \(G_3\),然后直接在 \(G_2\)\(G_3\) 拼起来的图中跑 bfs 即可,即 bfs 过程中将两个图的 bitset 或起来即可。

最后复杂度为 \(O(\frac{nq}{B} + q \frac{B^2}{\omega} + \frac{n^2}{\omega})\),取 \(B=300\) 即可通过。

注意每个块内要清空的数组的清空的范围。

#include<bits/stdc++.h>
#define double long double
using namespace std;
const int N=5e4+10,M=1e5+10,len=300,K=len+10;
bitset<4*K>s1[N],s2[4*K],s3[4*K];
int op[M],U[M],V[M],A[M],B[M],n,m,q,c[M],vis[M],cnt,vis1[N],ss[N],Ans,du[N];
int dfn[N],low[N];stack<int>s;
vector<int>g1[N],g2[N];
int anss[M],mp[4*K][4*K],mp1[N];
inline int read(){
	int ans=0,f=1;
	char c=getchar();
	while(c<48||c>57) (c==45?f=-1:1),c=getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
	return ans*f;
}
void tarjan(int u){
	dfn[u]=low[u]=++cnt;s.push(u),vis1[u]=1;
	for (auto v:g1[u]) 
		if (!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}	
		else if (vis1[v]) low[u]=min(low[u],dfn[v]);
	if (dfn[u]==low[u]){
		Ans++;
		while(s.top()^u){
			int x=s.top();s.pop();
			ss[x]=Ans,vis1[x]=0;
		}
		int x=s.top();s.pop();
		ss[x]=Ans,vis1[x]=0;
	}
}
inline bool bfs(int x,int y){
	bitset<4*K>tmp;tmp.set();
	queue<int>q;q.push(x);
	while(!q.empty()){
		int u=q.front();q.pop();
		bitset<4*K>xx=(tmp&(s2[u]|s3[u]));
		for (int v=xx._Find_first();v<4*K;v=xx._Find_next(v)){
			if (v==y) return 1;
			q.push(v),tmp.reset(v);
		}
	}
	return 0;
}
main(){
	n=read(),m=read(),q=read();
	for (int i=1;i<=m;i++){
		int u=read(),v=read();
		U[i]=u,V[i]=v;
		c[i]=1;
	}
	for (int i=1;i<=q;i++){
		op[i]=read();
		if (op[i]==1) A[i]=read();
		if (op[i]==2) A[i]=read(),B[i]=read();
	}
	for (int l=1;l<=q;l+=len){
		vector<int>tmp;
		int r=min(q,l+len-1);
		for (int i=1;i<=n;i++) dfn[i]=low[i]=vis1[i]=ss[i]=du[i]=0;
		for (int i=1;i<=n;i++) s1[i].reset(),g1[i].clear(),g2[i].clear();
		for (int i=1;i<=m;i++) vis[i]=0;
		for (int i=l;i<=r;i++) if (op[i]==1) vis[A[i]]=1,tmp.push_back(U[A[i]]),tmp.push_back(V[A[i]]); else tmp.push_back(A[i]),tmp.push_back(B[i]);
		for (int i=1;i<=m;i++) if (!vis[i]&&c[i]==1) g1[U[i]].push_back(V[i]);
		sort(tmp.begin(),tmp.end());tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
		for (int i=0;i<tmp.size();i++) mp1[tmp[i]]=i;
		cnt=Ans=0;
		for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
		for (int i=1;i<=n;i++) 
			for (auto j:g1[i]) if (ss[i]^ss[j]) g2[ss[i]].push_back(ss[j]),du[ss[j]]++;
		for (int i=0;i<tmp.size();i++) s1[ss[tmp[i]]].set(i);
		queue<int>q;vector<int>topsort;
		for (int i=1;i<=Ans;i++) if (!du[i]) q.push(i);
		while(!q.empty()){
			int u=q.front();q.pop();topsort.push_back(u);
			for (auto v:g2[u]) if (--du[v]==0) q.push(v);
		}
		reverse(topsort.begin(),topsort.end());
		for (auto i:topsort) for (auto j:g2[i]) s1[i]|=s1[j]; 
		for (int i=0;i<tmp.size();i++)
			for (int j=0;j<tmp.size();j++) if (s1[ss[tmp[i]]][j]) s2[i].set(j);
		for (int i=1;i<=m;i++) if (vis[i]&&c[i]) mp[mp1[U[i]]][mp1[V[i]]]++,s3[mp1[U[i]]].set(mp1[V[i]]); 
		for (int i=l;i<=r;i++) 
			if (op[i]==2) anss[i]=bfs(mp1[A[i]],mp1[B[i]]);
			else{
				int u=U[A[i]],v=V[A[i]];
				if (c[A[i]]){
					mp[mp1[u]][mp1[v]]--;
					if (mp[mp1[u]][mp1[v]]==0) s3[mp1[u]].reset(mp1[v]);
				}
				else{
					mp[mp1[u]][mp1[v]]++;
					if (mp[mp1[u]][mp1[v]]) s3[mp1[u]].set(mp1[v]);
				}
				c[A[i]]^=1;
			}
		for (int i=0;i<tmp.size();i++) for (int j=0;j<tmp.size();j++) mp[i][j]=0;
		for (int i=0;i<tmp.size();i++) s2[i].reset(),s3[i].reset();
	}
	for (int i=1;i<=q;i++) if (op[i]==2) puts(anss[i]?"YES":"NO");
	return 0;
}
posted @ 2026-01-11 19:34  OTn53_qwq  阅读(1)  评论(0)    收藏  举报