本题解题方法是并查集维护额外信息解决问题
记录每个节点到父结点的距离d[i],会有以下三种情况
d[i]%3=0, p[i]与i是统一种动物
d[i]%3=1 i吃p[i]
d[i]%3=2 p[i]吃i
在代码之前解释一下这个并查集find函数吧
如果一个节点的父节点就是整个集合的根节点,则find递归回溯过程中d[x]+=0;
所以对于所有路径已经压缩过的节点,他们的d[x]在进行find操作时时不会受到影响,也就是说此时的find函数和普通并查集函数的效果相同。
而如果该节点的父节点不是整个集合的根节点,比如如下情况,讲x这个集合合并到y上会出现以下情况。
对于这种情况,并查集会一直这样保存,直到下一次对x进行查询,也就是对x进行find操作,此时我们会将并查集更新成如下情形,并且d[x]的值更新为x到py的距离。
直接上y总的代码吧
#include <iostream>
using namespace std;
const int N = 50010;
int n, m;
int p[N], d[N];
int find(int x)
{
if (p[x] != x)
{
int t = find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;
while (m -- )
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (x > n || y > n) res ++ ;
else
{
int px = find(x), py = find(y);
if (t == 1)
{
if (px == py && (d[x] - d[y]) % 3) res ++ ;
else if (px != py)
{
p[px] = py;
d[px] = d[y] - d[x];
}
}
else
{
if (px == py && (d[x] - d[y] - 1) % 3) res ++ ;
else if (px != py)
{
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
}
}
printf("%d\n", res);
return 0;
}
/*作者:yxc
链接:https://www.acwing.com/activity/content/code/content/45325/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
·