【题解】CF776D

一:【题意】

现在给出一些门的状态(开或者关),你还有一些遥控器,每个可以使得一个集合的门的开关状态翻转,每个门只被最多两个遥控器控制,问是否能让所有门打开
\(n,m<=10^5\)

二:【解法】

对于每个遥控器,1表示按,0表示不按
门初始为关:则两个遥控器仅有一个为1
门初始为开:则两个遥控器同0或同1
可以转化为2-SAT求解

三:【代码】

#include<bits/stdc++.h>
#define inf 2e9
#define Pair pair<int,int>
#define l first
#define r second
using namespace std;
const int N=1e5+10;int n,m;
int a[N];
Pair bl[N];
vector<int> mp[N*2];

int low[N*2],dfn[N*2],cnt;
int scc[N*2],idx;
vector<int> st;
void Tarjan(int u,int pa){
	low[u]=dfn[u]=++cnt;
	st.push_back(u);
	for(auto v:mp[u]){
		if(v==pa) continue;
		if(!dfn[v]){
			Tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else if(!scc[v]) low[u]=min(low[u],dfn[v]);
	}
    //cout<<"==>"<<low[u]<<" "<<dfn[u]<<"\n";
	if(low[u]==dfn[u]){
		idx++;
		while(1){
			int x=st.back();st.pop_back();
			scc[x]=idx;
			if(x==u) break;
		}
	}
}
void SCC(){
	for(int i=1;i<=2*m;i++){
		if(!dfn[i]) Tarjan(i,0);
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++){
		int x;cin>>x;
		while(x--){
			int k;cin>>k;
			if(bl[k].l) bl[k].r=i;
			else bl[k].l=i;
		}
	}
	for(int i=1;i<=n;i++){
		int l=bl[i].l,r=bl[i].r;
        //cout<<"-->"<<l<<" "<<r<<"\n";
		if(a[i]==0){	
			mp[l].push_back(r+m);
			mp[l+m].push_back(r);
			mp[r].push_back(l+m);
			mp[r+m].push_back(l);
		}
		else{
			mp[l].push_back(r);
			mp[l+m].push_back(r+m);
			mp[r].push_back(l);
			mp[r+m].push_back(l+m);
		}
	}
	SCC();
    //for(int i=1;i<=n;i++) cout<<scc[i]<<" "<<scc[i+n]<<"\n";
	for(int i=1;i<=m;i++){
		if(scc[i]==scc[i+m]){
			cout<<"NO\n";
			return 0;	
		} 
	}
	cout<<"YES\n";
	return 0;
}
posted @ 2026-01-13 10:14  Ming3398  阅读(9)  评论(0)    收藏  举报