题目分析
- 该代码实现了一个动态集合管理系统,支持三种操作:合并集合、切换元素状态、查询集合中是否- 存在活跃元素。核心数据结构为并查集,结合状态标记数组和计数器。
- 关键数据结构与函数
初始化
- fa[N]:并查集父节点数组,初始时每个元素自成一集合。
- cnt[N]:记录每个集合中活跃元素的数量。
- f[N]:标记元素是否活跃(true表示活跃)。
- 路径压缩:查找时直接指向根节点,优化后续查询效率。
- 按大小合并:将较小集合的根指向较大集合的根,并累加活跃元素计数。
- 动态更新元素活跃状态,并同步调整所属集合的计数器。
操作处理流程
- 合并集合(op=1)
- 输入两个元素u和v,合并其所属集合。
- 切换状态(op=2)
- 输入元素u,反转其活跃状态并更新集合计数器。
- 查询集合(op=3)
- 输入元素u,检查其所属集合是否存在活跃元素(cnt[find(u)] > 0)。
复杂度分析
- 时间复杂度:单次find操作接近O(α(n))O(\alpha(n))O(α(n))(反阿克曼函数),整体操作复杂度为O(q⋅α(n))O(q \cdot \alpha(n))O(q⋅α(n))。
- 空间复杂度:O(n)O(n)O(n),用于存储父节点、计数器和状态数组。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,q,fa[N],cnt[N];
bool f[N];
int find(int x)
{return (x==fa[x]?x:fa[x]=find(fa[x]));
}
void merge(int x,int y)
{x=find(x),y=find(y);if(x!=y) fa[x]=y,cnt[y]+=cnt[x];
}
void change(int x)
{int fx=find(x);if(f[x]) cnt[fx]--;else cnt[fx]++;f[x]=!f[x];
}
signed main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n>>q;for(int i=1;i<=n;i++) fa[i]=i;int op,u,v;while(q--){cin>>op;if(op==1){cin>>u>>v;merge(u,v);}else if(op==2){cin>>u;change(u);}else{cin>>u;if(cnt[find(u)]) cout<<"Yes"<<'\n';else cout<<"No"<<'\n';}}return 0;
}