【 newcoder 】幼儿园战争 【并查集+删并查】

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
幼儿园的孩子们正在做游戏,每个人都有自己的帮派,帮派之间打架,然后赢者吞并弱者扩大自己的势力。最开始每个孩子的帮派中只有自己,然后接下来有会有两个人打架,这两个人会集结自己所属的势力开始打架,打赢的一方就会吞并输的一方,当然如果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 = 100000*3;
const int MAXM = 1e6 ;

int pre[MAXN],pos[MAXN],num[MAXN],tot,sz;
void Init(int n){  // 初始化
    for(int i=0;i<=n;i++){
        pos[i]=pre[i]=i;
        num[i]=1;
    }
    tot=n; sz=n;
}
int Find(int x){  // 查
    return x==pre[x]?x:(pre[x]=Find(pre[x]));
}
bool Join(int x,int y){ // x合并到y上,注意传参顺序
    x=pos[x]; y=pos[y];
    int fx=Find(x); int fy=Find(y);
    if(fx==fy) return false;
    pre[fx]=fy; num[fy]+=num[fx];
    sz--;
    return true;
}
bool Del(int x){  //删
    int fx=Find(pos[x]);
    if(num[fx]==1) return false;
    num[fx]--;
    pos[x]=++tot; pre[tot]=tot; num[tot]=1;
    sz++;
    return true;
}
int main(){
    int n,m; int ncase=1;
    int T;scanf("%d",&T);
    while(T--){
        printf("Case #%d:\n",ncase++);
        int n,m; scanf("%d%d",&n,&m);
        Init(n); char op[10];
        while(m--){
            scanf("%s",op);
            if(op[0]=='q') printf("%d\n",sz);
            else if(op[0]=='f'){
                int x,y;scanf("%d%d",&x,&y);
                int fx=Find(pos[x]); int fy=Find(pos[y]);
                if(fx==fy) continue;
                if(num[fx]==num[fy]) puts("Either is winner!");
                else if(num[fx]<num[fy]) {
                    Join(x,y);
                    printf("%d is winner!\n",y);
                }else {
                    Join(y,x);
                    printf("%d is winner!\n",x);
                }
            }else if(op[0]=='r') {
                int x;scanf("%d",&x);
                Del(x);
            }else if(op[0]=='t') {
                int x,y;scanf("%d%d",&x,&y);
                Del(y); Join(y,x);
            }
        }
    }
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值