G - Por Costel and the Match Gym - 100923H(种类并查集)

G - Por Costel and the Match Gym - 100923H

Oberyn Martell and Gregor Clegane are dueling in a trial by combat. The fight is extremely important, as the life of Tyrion Lannister is on the line. Oberyn and Gregor are measuring their skill in combat the only way the two best fighters in Westeros can, a match of Starcraft. The one who supervises the match in none other than Por Costel the pig.

Oberyn and Gregor are both playing the Terrans, and they confront each other in the middle of the map, each with an army of Marines. Unfortunately, pigs cannot distinguish colors that well, that is why Por Costel can’t figure out which marine belongs to which player. All he sees is marines in the middle of the map and, from time to time, two marines shooting each other. Moreover, it might be the case that Por Costel’s imagination will play tricks on him and he will sometimes think two marines are shooting each other even though they are not.

People are starting to question whether Por Costel is the right person for this important job. It is our mission to remove those doubts. You will be given Por Costel’s observations. An observation consists in the fact that Por Costel sees that marine and marine are shooting each other. We know that marines in the same team (Oberyn’s or Gregor’s) can never shoot each other. Your task is to give a verdict for each observation, saying if it is right or not.

An observation of Por Costel’s is considered correct if, considering this observation true and considering all the correct observations up to this point true, there is a way to split the marines in “Oberyn’s team” and “Gregor’s team” such that no two marines from the same team have ever shot each other. Otherwise, the observation is considered incorrect.

“Elia Martell!!! You rushed her! You cheesed her! You killed her SCVs!”

Input
The input file meciul.in will contain, on its first line, the number of tests (). A test has the following structure: the first line contains integers () and () and the next lines each contain a pair of integers and () describing an observation of Por Costel’s.

Output
The output file meciul.out will contain one line for each of Por Costel’s observations, on each test. The line will contain “YES” if the observation is correct and “NO” otherwise. It is not necessary to leave extra spacing between the outputs of different test cases.

Example
Input
1
3 3
1 2
2 3
1 3
Output
YES
YES
NO
题意:就是两个阵营的敌人打仗,同一阵营的人不能相互攻打,输入小兵的编号,直到出现矛盾的句子,之前的小兵都默认为不在同一阵营。要注意可能出现的情况,比如输出三组数据
1 2
3 4
1 3
这个时候如果直接连接小兵的编号,可能出现的情况是1和2分别放到两个集合里,而可能出现的情况就是两个集合分别是13,24或者14,23.如果是前者则第三句输出为no。为了防止这种情况的出现,集合里在连接并查集的时候需要这样连接:(假设1的敌人是1‘ ,2的敌人是2‘,则1 2是敌人的话,那么1和2’,2和1’就是同一阵营,放入两集合的元素就成了12’和1’2,这样就能避免上述情况。但是1’ 2’要如何表示呢,这里我们可以借助离散化表示为1+n和2+n,其实不是+n也可以,只要加的数大于n就行。用代码表示就是 Merge(u, v+n); Merge(u+n, v);)这是第一种方法。
第二种方法就是种类并查集。同一阵营的关系表示为0,敌人之间表示为1,敌人的敌人就是同一阵营的。
方法一:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int f[204014];

int get_f(int x);
void Merge(int x, int y);

int main(){
  //freopen("meciul.in", "r", stdin);
  //freopen("meciul.out", "w", stdout);
  int T, i, n, m, u, v;
  scanf("%d", &T);
  while(T--){
    scanf("%d %d", &n, &m);
    for(i = 1; i <= (n<<1); i++){
      f[i] = i;
    }
    for(i = 0; i < m; i++){
      scanf("%d %d", &u, &v);
      if(get_f(u) == get_f(v)){
        printf("NO\n");
        continue;
      }
      Merge(u, v+n);
      Merge(u+n, v);
      printf("YES\n");
    }
  }
  return 0;
}
int get_f(int x){
  if(x == f[x]) return x;
  return f[x] = get_f(f[x]);
}
void Merge(int x, int y){
    int t1 = get_f(x);
    int t2 = get_f(y);
    f[t2] = t1;
    return;
}

方法二:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f[500010],r[500010];
void init(int n)
{
    int i;
    for(i=1;i<=n;i++)
    {
        f[i] = i;
        r[i] = 0;
    }
}
int getf(int v)
{
    if(v == f[v])
        return v;
    else
    {
        int t = f[v];
        f[v] = getf(f[v]);
        if(r[v] == r[t])
            r[v] = 0;
        else
            r[v] = 1;
        return f[v];
    }
}
int main()
{
   //freopen("meciul.in", "r", stdin);
  //freopen("meciul.out", "w", stdout);
    int T,n,m,x,y,tx,ty;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        init(n);
        while(m--)
        {
            scanf("%d %d",&x,&y);
            tx = getf(x);
            ty = getf(y);
            if(tx == ty&&r[x] == r[y])
            {
                printf("NO\n");
                continue;
            }
            else
            {
                printf("YES\n");
                if(tx!=ty)
                {
                    f[ty] = tx;
                    if(r[x] == r[y])
                        r[ty] = 1;
                    else
                        r[ty] = 0;
                }
            }
        }
    }
    return 0;
}



或者使用异或
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f[500010],r[500010];
void init(int n)
{
    int i;
    for(i=1;i<=n;i++)
    {
        f[i] = i;
        r[i] = 0;
    }
}
int getf(int v)
{
    if(v == f[v])
        return v;
    else
    {
        int t = f[v];
        f[v] = getf(f[v]);
        r[v] = r[v]^r[t];
        return f[v];
    }
}
int main()
{
 freopen("meciul.in", "r", stdin);
   freopen("meciul.out", "w", stdout);
    int T,n,m,x,y,tx,ty;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        init(n);
        while(m--)
        {
            scanf("%d %d",&x,&y);
            tx = getf(x);
            ty = getf(y);
            if(tx == ty&&r[x] == r[y])
            {
                printf("NO\n");
                continue;
            }
            else
            {
                printf("YES\n");
                if(tx!=ty)
                {
                    f[ty] = tx;
                    r[ty] = r[x]^r[y]^1;
                }
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值