并查集怎么搞?POJ1182 食物链

    技术2025-09-20  42

    文章目录

    并查集操作初始化查询元素的"祖先"查询元素是否同组合并 POJ1182 食物链题解AC代码 Tips

    并查集

    并查集是一种用来管理元素分组情况的数据结构。 可以进行如下操作: · 查询元素a和元素b是否属于同一组; · 合并元素a和元素b所在的组。

    操作

    初始化

    int par[N], dth[N]; void init(int n) { for (int i = 0; i <= n; i++) { par[i] = i; dth[i] = 0; } }

    查询元素的"祖先"

    祖先:元素所在的组中最顶层的结点,即par[x] = x的结点。

    int find(int x) { return x == par[x] ? x : find(par[x]); } int find(int x) { while(x!=par[x]) x = par[x]; return x; }

    查询元素是否同组

    bool same(int x, int y) { return find(x) == find(y); }

    合并

    void unite(int x, int y) { x = find(x); y = find(y); if (x == y) return; else par[x] = y; }

    POJ1182 食物链

    题解

    这里有三种生物A、B、C。 食物链为:A->B->C->A。 对于输入的数据,我们并不能确定是这三种中的哪一种,当然,我们也不需要确定,只需要推导出矛盾的点就可以。

    对于任意生物X, X_n表示其为A,X_2n表示其为B, X_3n表示其为C。 那么如果我们得到a吃b的信息,就可以得出: a属于n && b属于2n, a属于2n && b属于3n, 以及a属于3n && b 属于n的信息。 如果接下来出现与这些情况不符的信息,就可以推定其真值为假。

    同理,如果我们得到a,b同类的消息,就可以得出: a属于n && b属于n, a属于2n && b属于2n, 以及a属于3n && b 属于3n的信息。 如果接下来出现与这些情况不符的信息,就可以推定其真值为假。

    AC代码

    #include <iostream> using namespace std; //#pragma GCC optimize(2) #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define ull unsigned long long #define ll long long #define rep(i, x, y) for(int i=x;i<=y;i++) #define mms(x, n) memset(x, n, sizeof(x)) #define mmc(a, b) memcpy(a, b, sizeof(b)) #define INF (0x3f3f3f3f) #define mod (ull)(1e9+7) typedef pair<int, int> P; const int N = 5e4 + 10; int n, k; int par[N * 3]; void init(int t) { for (int i = 1; i <= t; i++) { par[i] = i; } } int find(int x) { return x == par[x] ? x : find(par[x]); } void unite(int x, int y) { x = find(x); y = find(y); if (x == y) return; else par[x] = y; } bool same(int x, int y) { return find(x) == find(y); } int main() { scanf("%d%d", &n, &k); int cnt = 0; init(n * 3); while (k--) { int d, x, y; scanf("%d%d%d", &d, &x, &y);//1-N if (x <= 0 || y <= 0 || x > n || y > n || (d == 2 && x == y)) { cnt++; continue; } if (d == 1) { if (same(x, y + n) || same(x, y + 2 * n)) cnt++; else { unite(x, y); unite(x + n, y + n); unite(x + 2 * n, y + 2 * n); } } else if (d == 2) { if (same(x, y) || same(x, y + 2 * n)) cnt++; else { unite(x, y + n); unite(x + n, y + 2 * n); unite(x + 2 * n, y); } } } printf("%d\n", cnt); return 0; }

    Tips

    笔者开始用的关闭同步流的cin和cout,wa了三发hhhh。 scanf比它快。 此外输出\n比endl快。


    觉得不错的话记得点个赞呀~~你的赞就是笔者最大的动力

    Processed: 0.011, SQL: 9