题目描述:
有n个房子  起始时有的开有的关, 有m个开关每个开关控制几个房间(改变一次全部房子的状态就改变  原来开(开->关)或者 原来 关(关->开)),但一个房间恰好由两个开关控制
问能否同时打开n个房子
2 ≤ n ≤ 10^5, 2 ≤ m ≤ 10^5
分析:
假如不能同时打开n个房子 那么比会有一个开关同时出现打开和关闭,所以将开关的情况都放在一颗树上 比如:两个开关x,y 如果对应的门关则 x开,y不开,或则y开,x不开  当问打开时也有相同的道理
如果同一个开关 开或不开同时出现在了一棵树上则不能同时打开全部门;
显然这种方法是用并查集搜索,注意查完以后立刻更新该点指向的根节点,否则会超时
ac代码:
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+2;
int switch1[MAX*2];
vector<int> door[MAX];
int find(int x){
    if(switch1[x]==x)return x;
    else return switch1[x]=find(switch1[x]);
}
void merge(int a,int b){
    int x=find(a),y=find(b);
    if(x!=y) switch1[x]=y;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m;
    int vis[MAX];
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>vis[i];
    for(int i=1;i<=2*m;i++)switch1[i]=i;
    for(int i=1;i<=m;i++){
        int number;
        cin>>number;
        for(int j=1;j<=number;j++){
            int door1;
            cin>>door1;
            door[door1].push_back(i);
        }
    }
    for(int i=1;i<=n;i++){
        int swi1=door[i][0],swi2=door[i][1];
        if(!vis[i]){
            merge(swi1,swi2+m);//加个m表示关
            merge(swi1+m,swi2);
        }
        else{
            merge(swi1,swi2);
            merge(swi1+m,swi2+m);
        }
    }
    int flag=0;
    for(int i=1;i<=m;i++)
        if(find(i+m)==find(i)) {
            flag=1;
            break ;
        }
//    }
   flag==1?puts("NO"):puts("YES");
}