• POJ1182【种类并查集】


    思路:

    ---来源百度

    0表示它与根结点为同类,
    1表示它吃根结点,
    2表示它被根结点吃。
    判断两个点a, b的关系,我们令p = Find(a), q = Find(b),即p, q分别为a, b子树的根结点。
    1. 如果p != q,说明a, b暂时没有关系,那么关于他们的判断都是正确的,然后合并这两个子树。这里是
    关键,如何合并两个子树使得合并后的新树能保证正确呢?这里我们规定只能p合并到q(刚才说过了,启发式合并的优化效果并不那么明显,如果我们用启发式合并,就要推出两个式子,
    而这个推式子是件比较累的活...所以一般我们都规定一个子树合到另一个子树)。
    那么合并后,p的relation肯定要改变,那么改成多少呢?
    这里的方法就是找规律,列出部分可能的情况,就差不多能推出式子了。这里式子为:
    tree[p].relation = (tree[b].relation - tree[a].relation + 2 + d) % 3; 这里的d为判断语句中a, b的关系。
    还有个问题,我们是否需要遍历整个a子树并更新每个结点的状态呢?
    答案是不需要的,因为我们可以在Find()函数稍微修改,即结点x继承它的父亲(注意是前父亲,因为路径压缩后父亲就会改变),
    即它会继承到p结点的改变,所以我们不需要每个都遍历过去更新。

    2. 如果p = q,说明a, b之前已经有关系了。那么我们就判断语句是否是对的,同样找规律推出式子。
    即if ( (tree[b].relation + d + 2) % 3 != tree[a].relation ), 那么这句话就是错误的。

    3. 再对Find()函数进行些修改,即在路径压缩前纪录前父亲是谁,

    然后路径压缩后,更新该点的状态(通过继承前父亲的状态,这时候前父亲的状态是已经更新的)。

    //#include<bits/stdc++.h>
    //using namespace std;
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    
    const int N=5e4+10;
    int pre[N];
    int val[N];
    int n,m,ans;
    
    int Find(int x)
    {
        if(x==pre[x])
            return x;
        int tmp=pre[x];
        pre[x]=Find(tmp);
        val[x]=(val[x]+val[tmp])%3;
        return pre[x];
    }
    
    void Merge(int x,int y,int k)
    {
        int xx=Find(x);
        int yy=Find(y);
        if(xx==yy)
        {
            if(k==2&&(val[y]+k+2)%3!=val[x])
                ans++;
            if(k==1&&val[x]!=val[y])
                ans++;
        }
        else
        {
            pre[xx]=yy;
            val[xx]=(val[y]-val[x]+2+k)%3;
        }
    }
    
    int main()
    {
    	int temp,x,y;
        scanf("%d%d",&n,&m);
        ans=0;
        for(int i=1;i<=n;i++)
        {
            pre[i]=i;
            val[i]=0;
        }
        while(m--)
        {
            scanf("%d%d%d",&temp,&x,&y);
            if((x>n||y>n)||(temp==2&&x==y)){
                ans++;
                continue;
            }
            Merge(x,y,temp);
        }
        printf("%d
    ",ans);
    	return 0;
    }
    
    然后了解了一下启发式合并,无语。。就是一个智力活。。。
    直观感觉就是哪个好我咋合并.

    难点就是构造关系(权值):

    元素与元素之间关系的转化。

    父子结点间关系的转化。

  • 相关阅读:
    CentOS7安装Dnsmasq并更新最新版
    VMware vCenter Server Appliance(VCSA )6.7 部署,许可证破解
    vsphere6.7虚拟机与ESXI时间同步
    oracle使用存储过程返回数据集
    如何让CheckBoxList横着显示
    在oracle中创建自动增长字段
    oracle 11g安装客户端后使用ps/sql连接提示TNS适配器错误的解决办法
    myeclipse 网站项目部署失败
    Opera Dragonfly本地化
    ExtJs的fireEvent事件
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777447.html
Copyright © 2020-2023  润新知