哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)G - 幼儿园战争...

题目描述

幼儿园的孩子们正在做游戏,每个人都有自己的帮派,帮派之间打架,然后赢者吞并弱者扩大自己的势力。最开始每个孩子的帮派中只有自己,然后接下来有会有两个人打架,这两个人会集结自己所属的势力开始打架,打赢的一方就会吞并输的一方,当然如果x,y是一个势力就不会打起来。有些聪明的小朋友会将自己的糖分给其他小朋友引诱他离开所属势力加入到自己势力。又有一些小朋友会对现在的势力不满,然后反叛出去自立门户。

作为打架的双方,只有人数大于另一方才能打赢。即:人数相等则没有输赢,两个帮派没有变化。

幼儿园里面共有N个孩子,接下来有M次操作,操作有如下4种
1)  query      查询现在有多少个势力。
2)  fight x y  表示x,y打架.并输出"z is winner!"胜利的一方(z是x或y),如果没有打平则输出"Either is winner!".如果x,y属于同一个势力不会打架,当然也不用输出.
3)  tempt x y  表示x诱惑y、将y拉入x的势力。
4)  revolt x   表示x反叛,(自立门户)

 

输入描述:

第一行输入一个T代表有T组数据
接下来第一行有两个整数N,M,代表N个孩子,M次操作。
接下来有M行。每行输入有如下三种。
1) query
2) fight x y
3) tempt x y
4) revolt x
1<=T<=10;
1<=N,M<=100000;
1<=x,y<=N;

输出描述:

第一行输出"Case #x:",表示第x组测试数据。
接下来输出查询结果,每个结果占一行。
示例1

输入

1
5 9
query
tempt 1 2
query
fight 4 5
query
fight 2 3
query
revolt 2
query

输出

Case #1:
5
4
Either is winner!
4
2 is winner!
3
4

题解

并查集。

带有删除操作,和之前做过一个题一样,忘记是哪题了,要删除某个节点,在原集合中那个点就不管了,再开一个新节点就可以。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e5 + 10;
int f[maxn];
int b[maxn];
int c[maxn];
int T, n, m;
int block;
char op[20];

int Find(int x) {
  if(x != f[x]) return f[x] = Find(f[x]);
  return f[x];
}

int main() {
  scanf("%d", &T);
  for(int cas = 1; cas <= T; cas ++) {
    printf("Case #%d:\n", cas);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= 500000; i ++) {
      f[i] = i;
      c[i] = 1;
      b[i] = i;
    }
    block = n;
    while(m --) {
      scanf("%s", op);
      int x, y, fx, fy;
      if(op[0] == 'q') {
        printf("%d\n", block);
      } else if(op[0] == 'f') {
        scanf("%d%d", &x, &y);
        fx = Find(b[x]);
        fy = Find(b[y]);
        if(fx == fy) continue;
        if(c[fx] == c[fy]) {
          printf("Either is winner!\n");
          continue;
        } else if(c[fx] > c[fy]) {
          c[fx] = c[fx] + c[fy];
          f[fy] = fx;
          block --;
          printf("%d is winner!\n", x);
        } else {
          c[fy] = c[fy] + c[fx];
          f[fx] = fy;
          block --;
          printf("%d is winner!\n", y);
        }
      } else if(op[0] == 't') {
        scanf("%d%d", &x, &y);
        fx = Find(b[x]);
        fy = Find(b[y]);
        if(fx == fy) continue;
        c[fy] --;
        if(c[fy] == 0) block --;
        n ++;
        b[y] = n;
        fx = Find(b[x]);
        fy = Find(b[y]);
        f[fy] = fx;
        c[fx] = c[fx] + c[fy];
      } else {
        scanf("%d", &x);
        fx = Find(b[x]);
        c[fx] --;
        if(c[fx] == 0) block --;
        n ++;
        b[x] = n;
        block ++;
      }
    }
  }
  return 0;
}

  

转载于:https://www.cnblogs.com/zufezzt/p/8065068.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值