zoukankan      html  css  js  c++  java
  • 【带权并查集】食物链 NOIP 2001

    Title: [NOI2001]食物链
    题目描述
    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。

    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。

    有人用两种说法对这N个动物所构成的食物链关系进行描述:

    第一种说法是“1 X Y”,表示X和Y是同类。

    第二种说法是“2 X Y”,表示X吃Y。

    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。

    当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

    1.当前的话与前面的某些真的话冲突,就是假话;
    2.当前的话中X或Y比N大,就是假话;
    3.当前的话表示X吃X,就是假话。

    你的任务是根据给定的N(1≤N≤50,000)和K句话(0≤K≤100,000),输出假话的总数。

    输入
    第一行是两个整数N和K,以一个空格分隔。

    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。

    输出
    只有一个整数,表示假话的数目

    样例输入
    Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

    100 7
    1 101 1
    2 1 2
    2 2 3
    2 3 3
    1 1 3
    2 3 1
    1 5 5
    样例输出
    3

    看看这道题吧。这道题我们可以把出现的每个动物看成一个点,建立一个图。这个图的定义如下:

    若x与y是同类,则连一条边x->y值为0;
    若x吃y,则连一条边x->y值为1;
    若x被y吃,则连一条边x->y值为2;
    

    如何判断在同一个联通集合中的x、y的类别?我们把x到根节点的距离mod 3设为wt[x],y到根节点的距离mod 3设为wt[y]。所以:

    当wt[y]-wt[x]≡0 mod 3时,x、y同类;
    当wt[y]-wt[x]≡1 mod 3时,x吃y;
    否则,y吃x;(画一个图想一想...)
    

    若x、y不在同一个集合内,我们就要把x、y的集合联通起来,即在两个根节点之间连一条线。

    设x的根节点为r1,y的根节点为r2,r1->r2的值为d。
    我们把连接后的集合根节点设为r2,即把r1接到r2后面。
    ∴wt[x]+=d
    ∴wt[y]-wt[x]-d≡1/0 mod 3 (1:x吃y;0:x与y是同类)“/”表示两种情况:“或”
    ∴d≡wt[y]-wt[x]-1/0 mod 3
    ∴d=((wt[y]-wt[x]-1/0)%3+3)%3
    

    所以代码就出来了:

    #include<cstdio>
    #include<cstring>
    int n,k,ans;
    int f[50001];
    int wt[50001];
     
    int root(int x)//路径压缩带权并查集
    {
        if(f[x]==-1) return x;
        int d=f[x];
        f[x]=root(f[x]);
        wt[x]+=wt[d];
        wt[x]%=3;//迟早要模3,就先模掉
        return f[x];
    }
     
    int main()
    {int a,b,c;
        memset(f,-1,sizeof f);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(b>n||c>n||(a==2&&b==c)){ans++;continue;}
            int r1=root(b);
            int r2=root(c);
            if(r1==r2)
            {
                if((wt[c]-wt[b])%3!=0&&a==1) ans++;
                else if(((wt[c]-wt[b])%3+3)%3!=1&&a==2) ans++;
            }
            else
            {
                if(a==2){f[r1]=r2;wt[r1]=((wt[c]-wt[b])%3-1+3)%3;}
                else{f[r1]=r2;wt[r1]=((wt[c]-wt[b])%3+3)%3;}
            }
        }
        printf("%d",ans);
    }
    
  • 相关阅读:
    面试官问我:记录存在就更新,不存在就插入有啥思路怎么办?愣着干嘛?进来白嫖啊! (上)
    面试官问我:char和varchar的区别 怎么办?愣着干嘛?进来白嫖啊!
    面试官竟然疯狂问我数据库的组提交?怎么办?愣着干嘛?进来白嫖呀!
    面试官疯狂问我联表查询怎么办? 愣着干嘛?进来白嫖啊!
    面试官狂问我各种锁怎么办?愣着干嘛?进来白嫖啊!
    面试被问:如何排查慢查询(执行计划)怎么办?愣着干嘛?进来白嫖呀!
    B站挂了之后出现的tengine是个啥?
    Python
    Python
    Python
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039525.html
Copyright © 2011-2022 走看看