zoukankan      html  css  js  c++  java
  • POj 1703 Find them, Catch them(关系并查集)

    题目: 戳我

    题意:城市中有两个社会团伙

    已知有n个人:编号为1~n,和m个信息

    对于每个信息,D a b表明a和b属于不同的团伙,并且信息不会相互矛盾;A a b表示讯问a和b的关系,

    要求依次回答每个讯问,回答形式如下:

    Not sure yet.       //a和b的关系不确定

    In different gans.  //a和b属于不同的团伙

    In the same gang. //a和b属于同一个团伙

    回顾并查集的合并操作:我们总是将同类的集合进行合并,但此题给出的却是不同类的两个元素。

    抓住关键,城市的团伙只有两个,这个信息告诉我们:如果a和b不同类,b和c不同类,那么a和c必然属于一个团伙。

    更一般的,如果我们把编号看做顶点,关系看做连边。那么,如果顶点a,b之间的路径包含奇数条边,那么a与b属于不同的团伙,如果a,b之间的路径包含偶数条边,那么a与b属于同一个团伙。

    我们能够很容易的计算出元素x与根节点的“距离”(即路径上经过的边数)dis[x]。类似的,对于与x同属一个集合的任意元素y,我们也可以计算出y与根节点的“距离”dis[y]。那么,x与y的“距离”便可以用dis[x]+dis[y]表示。(注意,我们只关心“距离”的奇偶性,并不关心“距离”是否是最短的)

    代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    
    using namespace std;
    
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1e5+5;
    
    int bleg[maxn], dis[maxn], n, q;
    
    int find(int x)
    {
        int y = x, cnt = 0;
        while(y != bleg[y])
        {
            cnt += dis[y];
            y = bleg[y];
        }
        while(x != bleg[x])
        {
            int px = bleg[x], tmp = dis[x];
            dis[x] = cnt;
            bleg[x] = y;
            cnt -= tmp;
            x = px;
        }
        return y;
    }
    
    void Union(int a, int b)
    {
        int pa = find(a), pb = find(b);
        if(pa == pb) return;
        dis[pa] = dis[a] + dis[b] + 1;
        bleg[pa] = pb;
    }
    
    void Init()
    {
        for(int i = 0; i <= n; i++)
        {
            bleg[i] = i; dis[i] = 0;
        }
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%d %d", &n, &q);
            Init();
            while(q--)
            {
                int x, y;
                char op;
                scanf(" %c %d %d", &op, &x, &y);
                if(op == 'A')
                {
                    int pa = find(x), pb = find(y);
                    if(pa != pb)
                    {
                        puts("Not sure yet.");
                    }
                    else if((dis[x] + dis[y]) % 2 != 0)
                    {
                        puts("In different gangs.");
                        //printf("%d %d
    ", dis[x], dis[y]);
                    }
                    else 
                    {
                        puts("In the same gang.");
                    }
                }
                else 
                {
                    Union(x, y);
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    【CSS】330- 手把手教你玩转 CSS3 3D 技术
    【每周小回顾】4- 一起回顾上周精彩内容
    【CSS】329- 非常强!3行核心css代码的rate评分组件
    Android 高仿微信头像截取 打造不一样的自定义控件
    十三.200多万元得到的创业教训--用户体验就是人性
    十一. 没有这4项素质,别想在创业公司
    十二.200多万元得到的创业教训--app名字是关键
    十. 加班等于团队建设?
    Android 实现形态各异的双向侧滑菜单 自定义控件来袭
    九. 200多万元得到的创业教训--“雕爷”是忽悠吗?
  • 原文地址:https://www.cnblogs.com/tenlee/p/4547772.html
Copyright © 2011-2022 走看看