体育场

题目

 观众席每一行构成一个圆形,每个圆形由300个座位组成,对300个座位按照顺时针编号1到300,且可以认为有无数多行。现在比赛的组织者希望观众进入场地的顺序可以更加的有趣,在门票上并没有规定每个人的座位,而是与这个圈中某个人的相对位置,可以坐在任意一行。
  门票上标示的形式如下:A B x 表示第B个人必须在A的顺时针方向x个位置(比如A坐在4号位子,x=2,则B必须坐在6号位子)。
  现在你就座位志愿者在入场口检票。如果拿到一张门票,与之前给定的矛盾,则被视为是假票,如果无矛盾,视为真票。现在给定该行入场观众的顺序,以及他们手中的门票,请问其中有多少假票?

分析

并查集
假设没有 M 个条件,每一个人可以站在每一行上。
每增加一个条件,相当于将两行的人合并到一行上。每一行相当于一个集合,所以就可
以想到是并查集了。
假设并查集数组为 f[N],初始时是 f[i]=i;设一个距离数组 d[N],d[i]表示从 i 到 f[i]时的顺
时针距离。
如果给出的条件中的 a,b,dis中的 a,b 在同一集合,只需要判断(d[b]-d[a])%300 与 dis 的
关系,如果不相等,则矛盾,这张票是假票。
如果给出的条件中 a,b 在不同集合,我们就需要并查集合并,每次修改 f[i]的值时,维护
一下对应的 d[i]中 i 到 f[i]的距离。

程序

#include<iostream> 
using namespace std; 
int f[50001],d[50001]; 
int find(int k){ 
    if(f[k]==k) return k; 
    int t=f[k];
    f[k]=find(f[k]); 
    d[k]=(d[k]+d[t])%300; 
    return f[k]; 
} 
int main(){ 
    int n,m,a,b,x,root1,root2,ans=0;
    cin>>n>>m; 
    for(int i=1;i<=50000;i++)
        f[i]=i;
    for(int i=1;i<=m;i++){ 
        cin>>a>>b>>x; 
        root1=find(a);
        root2=find(b);
        if(root1!=root2){
            f[root2]=root1;
            d[root2]=(-d[b]+x+d[a]+300)%300;
        }
            else if((d[b]-d[a]+300)%300!=x)
                ans++;    
    }
    cout<<ans<<endl;
    return 0; 
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值