题目
观众席每一行构成一个圆形,每个圆形由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;
}