题目链接:Codeforces-766D-The Door Problem
首先可以知道一个钥匙只能使用0或1次。使用多次时与使用0或1次等效。
如果一个门状态是1,那么与这个门关联的两个钥匙要么都使用1次,要么都使用0次。
如果一个门状态是0,那么一个钥匙使用1次,另一个钥匙使用0次。
用u表示钥匙u使用0次,用u+m表示钥匙u使用1次。
然后使用并查集维护。如果u和u+m在同一个集合里,则出现矛盾。否则输出YES。
#include<bits/stdc++.h>
#define mp make_pair
#define pr pair<int,int>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
vector<int> k[maxn],d[maxn];
int r[maxn],father[maxn<<1];
int n,m;
int f(int x)
{
if(x==father[x]) return x;
father[x]=f(father[x]);
return father[x];
}
void Union(int x,int y)
{
x=f(x);y=f(y);
father[x]=y;
}
int main()
{
vector<int> k1,k2;
cin>>n>>m;
for(int i=0;i<m*2;i++) father[i]=i;
for(int i=1;i<=n;i++) cin>>r[i];
int x,tmp;
for(int i=0;i<m;)
{
cin>>x;
for(int j=0;j<x;j++)
{
cin>>tmp;
k[i].push_back(tmp);
d[tmp].push_back(i);
}
if(x==0) --m;
else ++i;
}
for(int i=1;i<=n;i++)
{
if(r[i]) Union(d[i][0],d[i][1]),Union(d[i][0]+m,d[i][1]+m);
else Union(d[i][0],d[i][1]+m),Union(d[i][0]+m,d[i][1]);
}
int tt=f(0);
for(int i=0;i<m;i++)
{
if(f(i)==tt) k1.push_back(i);
else k2.push_back(i);
}
for(int i=0;i<m;i++) if(f(i)==f(i+m)) {puts("NO");return 0;}
puts("YES");
return 0;
}