
ACM-ICPC寒假算法训练2:高级数据结构1:并查集2(带权并查集)
发布日期:2021-05-07 02:18:47
浏览次数:22
分类:精选文章
本文共 2287 字,大约阅读时间需要 7 分钟。
今天练习带权并查集
题1 :
题意及算法分析:
如果a和b在一棵树上,则他们之间有关系,如果dis[a]与dis[b]同为0 或 1,则是同一个帮派,否则是不同的帮派,如果不在一棵树上,则状态不明确。
AC代码:
#include#include const int maxn = 1e5 + 5;int n, m, t, p[maxn], dis[maxn];void init(){ for(int i = 1;i <= n;i++){ p[i] = i; dis[i] = 0; }}int find(int x){ if(x == p[x]) return x; int r = p[x]; p[x] = find(p[x]); dis[x] = (dis[x] + dis[r]) % 2; return p[x];}void merge(int x, int y){ int px = find(x), py = find(y); if(px != py){ p[px] = py; dis[px] = (dis[y] - dis[x] + 1) % 2; }}int main(){ scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); init(); while(m--){ char ch; int a, b; getchar(); scanf("%c %d %d",&ch,&a,&b); if('D' == ch) merge(a, b); else{ if(find(a) == find(b)){ if(dis[a] == dis[b]) printf("In the same gang.\n"); else printf("In different gangs.\n"); } else printf("Not sure yet.\n"); } } } return 0;}
题二:
题意及算法分析:
有三个种类,则dis(x, y)分三类:
0:他们是同类 1:x吃y 2:x被y吃这样分类有个好处:如果是同类:cmd = 1(1 - 1 = 0),x被y吃:cmd = 2(2 - 1 = 1)
这样就可以得到:x与y的状态可以由cmd直接得出。最初的权值:
因为最开始,自己和自己当然是一类生物,所以初始化的时候都是0(同类)
Find中的权值更新:
因为我们最终合并两棵树是合并他们的根,于是要得到dis(x, rx)
dis(x, rx) = (dis(x, rx) + dis(rx, rx)) % 3 也就是:dis[x] = (dis[x] + dis[r]) % 3Union的权值更新:
我们规定更新的方向:p[px] = py
也就是把py当作新的树根,把px接到py的孩子处 因为我更新的对象是x和y,所以需要通过关系:dis(x, y)来更新dis(rx, ry) 我们已经根据上面的讲述,得到dis(x, y) = cmd - 1 x->rx, y->ry, rx->ry 根据这个向量关系可以得到: dis(rx, ry) = dis(x, y) + dis(x, rx) - dis(y, ry) 所以代码就是: dis[px] = (cmd - 1 + dis[x] - dis[y] + 3) % 3 这里加3的原因是维护非负整数AC代码:
#includeconst int maxn = 5e4 + 5;int n, k, p[maxn], dis[maxn], ans;int find(int x){ if(x == p[x]) return x; int r = p[x]; p[x] = find(p[x]); dis[x] = (dis[x] + dis[r]) % 3; return p[x];}void merge(int type, int x, int y){ int px = find(x), py = find(y); if(px != py){ p[px] = py; dis[px] = (type - 1 + dis[y] - dis[x] + 3) % 3; }}int main(){ scanf("%d %d",&n, &k); for(int i = 1;i <= n;i++) p[i] = i, dis[i] = 0; while(k--){ int cmd, a, b; scanf("%d %d %d",&cmd, &a, &b); if(a > n || b > n || (2 == cmd && a == b)) ans++; else if(find(a) == find(b)){ if(1 == cmd && dis[a] != dis[b]) ans++; if(2 == cmd && dis[a] != (dis[b] + 1) % 3) ans++; } else merge(cmd, a, b); } printf("%d", ans); return 0;}
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2025年04月21日 00时41分00秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
GreenDao之注解
2021-05-14
Android使用Font Awesome
2021-05-14
主线程中Looper的轮询死循环为何没有阻塞主线程?
2021-05-14
Gradle实战四:Jenkins持续集成
2021-05-14
使用RestTemplate,显示请求信息,响应信息
2021-05-14
wgcloud运维监控系统错误:防篡改校验错误次数大于10次,不再上报数据
2021-05-14
为什么WGCLOUD安装完后,启动服务端打不开网页
2021-05-14
wgcloud网络监控出现负值
2021-05-14
ios 官方sample
2021-05-14
iOS 开发官方文档链接收集
2021-05-14
网易云面试(Android岗)之旅,差点被这些基础题绊了跟头。
2021-05-14
Android音视频开发之——音频非压缩编码和压缩编码
2021-05-14
linux学习笔记(四)基本用户管理与帮助命令
2021-05-14
小程序:防止父方法被子方法冒泡,使用catchtap
2021-05-14
vue报错 created hook错误
2021-05-14
单选框点击文字也能选中
2021-05-14
此主机支持Intel VT-x,但Intel VT-x 处于禁用状态。
2021-05-14
06-局部变量和全局变量
2021-05-14
12-面向对象1
2021-05-14