zoukankan      html  css  js  c++  java
  • 三个种类的并查集——pku1182(中上难度)

    这道题目,理解了好久,其实只要把关系图画一下,有些概念自然就知道了……
    当然也使我明白了,并查集因为通过路径压缩后,一个节点的find()过程,最多需要2次递归,最多一次修改……这样题目就理解了……
    View Code
    #include <stdio.h>
    #define max 50000+5
    int f[max];
    int r[max];
    /*
    rank[x]表示father[x]与x的关系
    rank[x] == 0 表示father[x]与x是同类
    rank[x] == 1 表示x吃father[x]
    rank[x] == 2 表示father[x]吃x
    */
    void make_set(int x)
    {
    f[x]
    =-1;
    r[x]
    =0;
    }
    int find_set(int x)
    {

    if (f[x]==-1) return x;
    int t=f[x];
    f[x]
    =find_set(t);//路径压缩

    r[x]
    =(r[t]+r[x])%3;
    //important. 更新r[]数组中x与代表元素的相对关系。更新原因:
    //代表元素在union_set操作中被改变了。
    //至于这个式子的推得.可以枚举rx与p[x], p[x]与x的关系,然后观察得到。
    //更好的方法是向量运算。
    return f[x];
    }
    void union_set(int x,int y,int d)
    {
    int a=find_set(x);
    int b=find_set(y);
    f[a]
    =b;
    r[a]
    = (r[y] - r[x]+ 2 + d ) % 3;
    //同上。这两个关系的推得实际上是这道题的关键所在。
    }
    int main()
    {
    int n,k;
    int d,x,y,lie=0;

    scanf(
    "%d%d",&n,&k);
    for (int i=0;i<max;i++)
    make_set(i);
    while (k--)
    {
    int a,b;
    scanf(
    "%d%d%d",&d,&x,&y);
    if (d==2&&x==y) {lie++;continue;}
    if (x>n||y>n) {lie++;continue;}
    a
    =find_set(x);
    b
    =find_set(y);

    if (a==b)
    {
    if (d==1&&r[x]!=r[y])
    lie
    ++;
    else
    {
    if (d==2&&r[x]!=(r[y]+1)%3)
    lie
    ++;
    }
    }
    else
    union_set(x,y,d);
    }
    printf(
    "%d\n",lie);
    return 0;
    }
  • 相关阅读:
    [CF1342D] Multiple Testcases
    [CF448D] Multiplication Table
    [CF459C] Pashmak and Buses
    [CF766E] Mahmoud and a xor trip
    [CF35E] Parade
    [CF15C] Industrial Nim
    [CF9D] How many trees?
    [CF19B] Checkout Assistant
    [CF22D] Segments
    [CF21D] Traveling Graph
  • 原文地址:https://www.cnblogs.com/huhuuu/p/1966302.html
Copyright © 2011-2022 走看看