并查集 并查集
//此处优化为更新x的祖先时顺便更新了x父亲的祖先也为x的祖先int ff(x){return fa[x]==x?x:fa[x]=ff(fa[x]);}int join(int x,int y){x=ff(x),y=ff(y);x=fa[y];}
P2661 [NOIP2015 提高组] 信息传递
用并查集难的地方是在寻找父亲和合并过程的变化。要了解合并和寻找过程对题目变量的影响。
一旦 i i i查询的 x x x和 i i i不是直接父子关系,继续向上查找合并就应该算成另外一轮,并且是当前轮之前的轮数确定的并集关系。
同时模板中查找父亲时顺便更新父亲的祖先的优化也不能加入,因为这个优化的作用在于将 x x x并查集内的所有节点都变成 x x x祖先的直接后继,将整个并集变成二层结构,从而减少 x x x的父亲查找其祖先的次数,但是这个次数恰恰是我们需要的轮数。
#include P1525 [NOIP2010 提高组] 关押罪犯 #include P1197 [JSOI2008]星球大战 #include
敌人的敌人是朋友,只要保存当前边的两个人原先有的敌人,再交叉将对方与自己的敌人合在一个并查集即可。这个题很像食物链,就是在扩展空间保存不同关系。
先将所有的连边存储起来,按顺序保存每个要炸毁的点,再连接那些不被炸毁的边,此时的连通块个数就是炸毁 k k k个点之后的连通块个数,相当于是最后的连通块个数,因此用栈来存储答案。接下来逆序遍历 k k k个要炸毁的点,每次添加一个点及其连边。每次连边都是将两个连通块变成一个,因此连通块总个数减少1。