码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P2024 食物链

时间:2020-04-14 10:35:52      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:假设   思想   带权并查集   play   iostream   rip   com   集合   space   

\(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 食物链

标签:假设   思想   带权并查集   play   iostream   rip   com   集合   space   

原文地址:https://www.cnblogs.com/czyty114/p/12695837.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!