并查集的复习
蒟蒻刚刚得到了教练给的VB网址便前往刷题:
教练:上面的题都是基础,你们自己好好练吧:
我:好耶!!冲冲!!
one hours later~
我:我去,这题是毒瘤吧,什么鬼并查集呀!
被逼无奈的我在洛谷上找到了题目。一看,蓝题!教练啊,不要虐我这个刚刚躺进复赛的蒟蒻。
好吧,看看大佬的题解,我终于弄明白了这个叫带权并查集的东东;
众所周知:并查集是用来合并集合的好东西,查找也很快但不到O(1)。我们用它来做最小生成树(kruskal)。便于我们判断一条边的两个节点是否存在同一个集合中。
比如说:
Cube Stacking POJ-1988 落谷5092
https://www.luogu.com.cn/problem/P5092
题面吗,自己看看。就是移动堆栈,判断每一个方块下方的方块数量;
思路便是在查询父亲时,利用回溯法,在查找的同时返回每一个节点的dis值,dis数组维护节点下方的方块数量;我觉得和dfs有相似之处,差不多一模一样;
1 #include<iostream> 2 using namespace std; 3 int n; 4 const int N=1e5+10; 5 int fa[N]; 6 int size[N]; 7 int dis[N]; 8 int find(int x){ 9 if(fa[x]==x){ 10 return x; 11 } 12 int father=find(fa[x];//向下层搜索但别慌 13 dis[x]+=dis[fa[x]];//更新dis值 14 fa[x]=father;//返回父亲 15 return father; 16 } 17 void merge(int x,int y){ 18 int fx=find(x); 19 int fy=find(y); 20 21 fa[fx]=fy;//路径压缩 22 dis[fx]+=size[fy];//父亲的dis值加上y所在集合的size 23 size[fy]+=size[fx];//下方集合的方块数++ 24 25 return ; 26 } 27 void query(int x){ 28 int ffx=find(x);//看似没用,实则有用目的是更新x的dis值 29 cout<<dis[x]<<endl; 30 } 31 int main() 32 { 33 cin>>n; 34 for(int i=1;i<=n;i++){ 35 fa[i]=i; 36 size[i]=1;//初始化 37 } 38 for(int i=1;i<=n;i++){ 39 char A; 40 cin>>A; 41 if(A=='M'){ 42 int x,y; 43 cin>>x>>y; 44 merge(x,y); 45 }else{ 46 int x; 47 cin>>x; 48 query(x); 49 } 50 } 51 return 0; 52 }
马上便是下一道毒瘤题(对我这种蒟蒻而言)
2.食物链 落谷2024 https://www.luogu.com.cn/problem/P2024
题意就是每次读入两者之间的关系,先特判前两种是假话的情况;
最后一种情况就分两种情况 1.两者是同类;2.两者不是同类;我们只用一个并查集来维护所有动物之间的关系,牛不牛逼~~~~
1.两者是同类,在判断两者是否在一个集合内,如果在一个集合内部,我们就用两个节点与父亲之间的关系来确定这句话是不是假话;如果不在,就合并,并更新关系;
2.两者不是同类,同上;
重点便是:我们怎么更新子节点与父节点之间的捕食关系,又怎样通过父节点来判断两者之间的关系;
接下来就到了最关键的时刻:::倾听大佬(当然不是我)的 讲解
重点的find函数:
1 int find(int a) 2 { 3 int fa=f[a]; 4 if (a!=fa) { 5 f[a]=find(fa);//找到爸爸先别慌~~ 6 re[a]=(re[a]+re[fa])%3;//完美的取模运算~~~ 7 return f[a]; 8 } 9 else return fa; 10 }
重点的merge函数:
1 f[f1]=f2; re[f1]=(3-re[a]+re[b])%3;//合并倒推与父亲的关系 又是取模运算~~~~~~~~~
1 int rela=(re[a]-re[b]+3)%3; //用两个节点与父亲的关系推出两者关系
全部代码:
1 #include<iostream> 2 using namespace std; 3 int f[100000],re[100000]; 4 int n,m,a,b,p,ans=0; 5 6 int find (int a){ 7 int fa=f[a]; 8 if(a!=fa){ 9 f[a]=find(fa); 10 re[a]=(re[a]+re[fa])%3; 11 return f[a]; 12 }else return fa; 13 } 14 15 16 int main() 17 { scanf("%d%d",&n,&m);//作为一道毒瘤题怎么能让你用cin呢??? 18 for(int i=1;i<=n;i++){ 19 f[i]=i; 20 re[i]=0;//自己不可能吃自己,都是同类 21 } 22 for(int i=1;i<=m;i++){ 23 scanf("%d%d%d",&p,&a,&b); 24 if((a>n||b>n)||(p==2&&a==b))//特判两种情况 25 ans++;continue; 26 } 27 if(p==1){ 28 int f1=find(a),f2=find(b); 29 if(f1==f2&&re[a]!=re[b]){//都是同类了怎么还能与父节点的关系不同呢 30 ans++;continue; 31 }else if(f1!=f2){ 32 f[f1]=f2; 33 re[f1]=(3-re[a]+re[b])%3;//膜拜大佬 34 35 } 36 } 37 if(p==2){ 38 int f1=find(a),f2=find(b); 39 if(f1==f2){ 40 int rela=(re[a]-re[b]+3)%3;//由父亲到儿子 41 if(rela!=1){ 42 ans++; 43 continue; 44 } 45 } 46 else{ 47 int f1=find(a),f2=find(b); 48 f[f1]=f2; 49 re[f1]=(3-re[a]+re[b]+1)%3;//以 下 犯 上(~^_^~) 50 } 51 } 52 } 53 cout<<ans; 54 return 0; 55 }
今天的复习到此结束,拜拜~~
看在我今天为小妹妹让座的份上,点个赞吧~~~~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效