Luogu P2024 食物链
Posted czyty114
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P2024 食物链相关的知识,希望对你有一定的参考价值。
【(Description)】https://www.luogu.com.cn/problem/P2024
一道带权并查集的题
这道题很重要的一点就是:
有(3)种不同的动物(A,B,C)。且(A)吃(B),(B)吃(C),(C)吃(A)
由此我们可以得到:对于一个动物,有它的同类、天敌、猎物。
按照我们并查集的思想:只要算出每个点到这个集合根节点的关系,就可以间接地算出每两两个点之间的关系了
设(d_x)表示(x)这个点到根节点的距离((mod;;3))
则:当(d_x=0)时,表示:根节点是(x)的同类
当(d_x=1)时,表示:根节点是(x)的猎物
当(d_x=2)时,表示:根节点是(x)的天敌
这里模(3)是因为:我们做的事情是在长度为(3)的环上的关系传递
那假设现在有两个动物(x,y)在同一个集合内,如何判断它们之间的关系?
当(d_x = d_y)时,显然(x)与(y)是同类
如何判断(x)吃(y)?根据前面的(0,1,2)的关系。打表即可发现:
(x)的同类的猎物等价于(x)的猎物 (=> d_x=0,d_y=2)
(x)的猎物的同类等价于(x)的猎物 (=> d_x=1,d_y=0)
(x)的天敌的天敌等价于(x)的猎物 (=> d_x=2,d_y=1)
则当(d_x=d_y+1)时,满足这个性质。
则当(d_x+1=d_y)时,自然就是(y)吃(x)
因此我们在合并两个集合的时候遵循上面的原则:
设(x,y)的祖先是(p,q)。则我们把(p)接到(q)上,(d_p=?)
当(x,y)是同类时,我们要使:
[d_x=d_y;(mod;;3)
]
则:
[d_x+d_p=d_y;(mod;;3)
]
[d_p=d_y-d_x;(mod;;3)
]
[d_p=(d_y-d_x+3)\% 3
]
同理,当(x)吃(y)时,我们要使:
[d_x=d_y+1;(mod;;3)
]
则:
[d_x+d_p=d_y+1;(mod;;3)
]
[d_p=d_y-d_x+1;(mod;;3)
]
[d_p=(d_y-d_x+4)\%3
]
(Code:)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=50010;
int n,K,f[N],d[N],res;
int find(int x)
{
if(f[x]!=x)
{
int root=find(f[x]);
d[x]=(d[x]+d[f[x]])%3;
f[x]=root;
}
return f[x];
}
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)f[i]=i;
while(K--)
{
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
if(x>n||y>n)
{
res++;
continue;
}
if(opt==1)
{
int p=find(x),q=find(y);
if(p==q)
{
if(d[x]!=d[y])
{
res++;
continue;
}
}
else
{
f[p]=q;
d[p]=(3-d[x]+d[y])%3;
}
}
else
{
int p=find(x),q=find(y);
if(p==q)
{
if(d[x]==d[y]||d[x]!=(d[y]+1)%3)
{
res++;
continue;
}
}
else
{
f[p]=q;
d[p]=(4-d[x]+d[y])%3;
}
}
}
printf("%d",res);
return 0;
}
以上是关于Luogu P2024 食物链的主要内容,如果未能解决你的问题,请参考以下文章