poj 1182 食物链(经典种类并查集)

时间:2022-04-01 14:14:52

看了大佬的博客,终于对种类并查集有了自己的理解。现写下这篇博客,加深自己对种类并查集的理解~
题目链接:http://poj.org/problem?id=1182
题目大意:都是中文没啥好说的。。。
思路:每个种类就相当于一个集团,给这个集团加个权值代表这个集团。(种类并查集也是加权并查集的一 种)。
主要是group(集团之后都用gp表示)
0 代表这个节点的和父节点的关系是同类
1代表这个节点吃他的父节点吃
2代表这个节点被他的父节点吃,也吃gp为1的节点
然后有了gp食物链就链接成功了。
然后是树的权值的更新
poj  1182 食物链(经典种类并查集)
并查集三部:
建树: 每个数的跟节点赋值为本身,gp为0,未被讨论的都属于0,初始化的时候用inline可以加速
find:找到这个数的根节点(递归还是函数都是可以的),在返回前,跟新一下这个节点和父节点的关系
gp[i]=(gp[i]+gp[pa[i]])%3;
unite:先进行路径压缩,更新权值 ,如果以前确定了关系,那么的话就在食物链内就可以直接验证真假关系,如果不在就并入食物链中
代码:
#include
const int max=50000+50;
int gp[max],pa[max];

inline void init(int n){
for(int i=1;i<=n;i++)
pa[i]=i,gp[i]=0;
}

int find(int x){
if(x==pa[x]) return x;
int fa=find(pa[x]);
gp[x]=(gp[x]+gp[pa[x]])%3;
return pa[x]=fa;
}

int unite(int d,int x,int y){
int fx=find(x);
int fy=find(y);
if(fx==fy){
if(d==1&&gp[x]!=gp[y]) return false;
if(d==2&&(gp[y]+1)%3!=gp[x]) return false;
return true;
}
gp[fx]=(gp[x]-gp[y]+3+d-1)%3;
pa[fx]=fy;
return true;
}

int main()
{
int n,m;
while(~scanf(“%d%d”,&n,&m))
{
init(n);
int d,x,y,sum=0;
for(int i=0;i