zoukankan      html  css  js  c++  java
  • P2024 [NOI2001]食物链

    链接:P2024

    -------------------------------

    建三个并查集空间太大了,应该写加权并查集

    -------------------------------

    这道题的关系是个环,转过来转过去的。我们的权值就定义成这个点与父节点的关系(0=同类,1=吃

    2=被吃)

    ------------------------------

    这样做,我们就要在find时如果搞路径压缩,就要麻烦一点,因为我们要把他与父节点的关系更新成与

    祖先节点的关系。

    非常易证得,关系就是与父节点的关系+与祖先节点的关系的和mod3的值(因为递归的原因,这个祖先节点最多就是父节点的父节点)

    int find(int x){
        if(x!=f[x])
        {
            int xx=f[x];
            f[x]=find(f[x]);
            g[x]=(g[x]+g[xx])%3;
        }
        return f[x];
    }
    find

    -----------------------------

    看一下题目,首先把两种白痴情况排除:自己吃自己和>n

    然后先考虑1的情况

    + 如果这俩祖先相同,就检查是不是同类,不是就ans++

    + 不同,就考虑合并祖先节点

    > 计算祖先节点的关系可以倒着考虑,假如x,y是他们祖先的祖先且y是x的祖先,那么他们原来的祖先什么关系?

    > 把y的祖先翻转,及变为3-g[y],然后就回归上面的线性求法了

    再考虑下2

    + 在同一棵树上就仿照着1做,因为关系是吃要加1

    + 不同也是中这么搞,记得+1

    而且合并的时候合并的是x,y的父亲,不是x,y。

        if((x>n||y>n)||(x==y&&fl==2)){
                ans++;
                continue;    
            }
            if(fl==1){
                if(find(x)==find(y)){
                    if(g[x]!=g[y]){
                        ans++;
                    }
                }
                else{
                    g[f[x]]=(g[y]-g[x]+3)%3;
                    f[f[x]]=f[y];
                }
            }
            if(fl==2){
                if(find(x)==find(y)){
                    if(g[x]!=(g[y]+1)%3){
                        ans++;
                    }
                }
                else
                {
                    g[f[x]]=(g[y]-g[x]+4)%3;
                    f[f[x]]=f[y];
                }
            }
    o

    -------------------------------------------------

    完整代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int fl,x,y;
    int g[500001];
    int f[500001];
    int n,k;
    int cnt;
    int find(int x){
        if(x!=f[x])
        {
            int xx=f[x];
            f[x]=find(f[x]);
            g[x]=(g[x]+g[xx])%3;
        }
        return f[x];
    }
    int ans;
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i){
        f[i]=i;
        g[i]=0;
        }
        for(int i=1;i<=k;++i){
            scanf("%d%d%d",&fl,&x,&y);
            if((x>n||y>n)||(x==y&&fl==2)){
                ans++;
                continue;    
            }
            if(fl==1){
                if(find(x)==find(y)){
                    if(g[x]!=g[y]){
                        ans++;
                    }
                }
                else{
                    g[f[x]]=(g[y]-g[x]+3)%3;
                    f[f[x]]=f[y];
                }
            }
            if(fl==2){
                if(find(x)==find(y)){
                    if(g[x]!=(g[y]+1)%3){
                        ans++;
                    }
                }
                else
                {
                    g[f[x]]=(g[y]-g[x]+4)%3;
                    f[f[x]]=f[y];
                }
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    Ac
  • 相关阅读:
    django之项目建立
    云监控服务比较
    2014 中华架构师大会 回顾
    计算字符串相似度算法——Levenshtein
    Maximum Likelihood 最大似然估计
    Laplacian eigenmap 拉普拉斯特征映射
    SparseLDA算法
    eigenvalues problem
    kernel function
    半监督学习[转]
  • 原文地址:https://www.cnblogs.com/For-Miku/p/11414050.html
Copyright © 2011-2022 走看看