ybtoj+C. 【例题3】食物链(NOI 1995)(并查集)

解法一:算距离,使用带边权并查集;

code:

#include<bits/stdc++.h>
using namespace std;
const int N=50010;
int d[N],p[N];
int find(int x){
    if(p[x]!=x){
        int t=find(p[x]);
        d[x]+=d[p[x]];//距离
        p[x]=t;
    }
    return p[x];
}
int main(){
    int n,m,res=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++) p[i]=i;
    while(m--){
        int t,x,y;
        cin>>t>>x>>y;
        if(x>n||y>n) res++;
        else{
            int px=find(x),py=find(y);
            if(t==1){
                if(px==py&&(d[x]-d[y])%3) res++;//判定冲突
                else if(px!=py){
                    p[px]=py;
                    d[px]=d[y]-d[x];
                }
            }else{
                if(px==py&&(d[x]-d[y]-1)%3) res++;//判定冲突
                else if(px!=py){
                    p[px]=py;
                    d[px]=d[y]-d[x]+1;//留存值
                }
            }
        }
    }
    cout<<res<<endl;
    return 0;
}

解法二:使用拓展域并查集,x+n表示x+n吃x,x+2*n表示x+2*n被x吃:

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 15e4 + 10;
int p[N], ans, n, k;
inline int find(int x) {
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}
inline bool check(int x, int y) { return find(x) == find(y); }
inline void hb(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) {
        p[x] = y;
    }
}
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n * 3; i++) p[i] = i;
    while (k--) {
        int z, x, y;
        cin >> z >> x >> y;
        if (x > n || y > n)
            ans++;
        else if (z == 1) {
            if (check(x, y + n) || check(x, y + 2 * n)) {
                ans++;
            } else {
                hb(x, y);
                hb(x + n, y + n);
                hb(x + 2 * n, y + 2 * n);
            }
        } else if (z == 2) {
            if (check(x, y) || check(x, y + 2 * n)) {
                ans++;
            } else {
                hb(x, y + n);
                hb(x + n, y + 2 * n);
                hb(x + 2 * n, y);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值