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

 

posted @ 2019-08-26 18:05  Simex  阅读(209)  评论(0编辑  收藏  举报