题目大意:
有很多行,每一行都是一个环,由
300
300
个座位组成,对
300
300
个座位按照顺时针编号
1
1
到。
门票上并没有规定每个人的座位,而是与这个圈中某个人的相对位置,可以坐在任意一行。
门票上标示的形式如下:
A,B,x
A
,
B
,
x
表示第
B
B
个人必须在的顺时针方向x个位置。
现在检票,如果拿到一张门票,与之前给定的矛盾,则被视为是假票,如果无矛盾,视为真票。
给定他们手中的门票,请问其中有多少假票?
有
N
N
个人,门票有张。
1<=m<=100,000
1
<=
m
<=
100
,
000
1<=A<=N,1<=B<=N,0<=X<300
1
<=
A
<=
N
,
1
<=
B
<=
N
,
0
<=
X
<
300
分析:
这题其实不用太在意行,
我们可以利用并查集去实现,
同一个集合的在同一行,
设
f[i]
f
[
i
]
表示
i
i
所在集中的根节点,
表示根节点到点
i
i
的距离,即根节点要走步到点
i
i
那么就很显然了,
每次如果个人
A,B
A
,
B
在同一集合,则利用
dis[]
d
i
s
[
]
判断真假,
不在同一集合则
设
A
A
的父亲为,
B
B
的父亲为,
B
B
在顺时针走
z
z
步的位置
因为有的位置关系,所以他们在同一行,所以
A,B,fA,fB
A
,
B
,
f
A
,
f
B
在同一行
那么
f[fB]
f
[
f
B
]
连向
fA
f
A
,
然后我们可以令
dis[fB]=dis[A]+z−dis[B]
d
i
s
[
f
B
]
=
d
i
s
[
A
]
+
z
−
d
i
s
[
B
]
因为
点
B
B
到的距离,为
B−>A,A−>fA
B
−
>
A
,
A
−
>
f
A
,即
z+dis[A]
z
+
d
i
s
[
A
]
,
即
fA
f
A
顺时针走
z+dis[A]
z
+
d
i
s
[
A
]
步到点
B
B
点到
fB
f
B
的距离,为
dis[B]
d
i
s
[
B
]
即
fB
f
B
顺时针走
dis[B]
d
i
s
[
B
]
到点
B
B
那么显然顺时针走
dis[A]+z−dis[B]
d
i
s
[
A
]
+
z
−
d
i
s
[
B
]
到点
fB
f
B
其他的
dis[]
d
i
s
[
]
更新则在并查集的压缩路径中判断
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 50005
using namespace std;
int dis[N], f[N], n, m, MOD = 300;
int Find(int x) {
if (f[x] == x) return x;
int y = f[x];
f[x] = Find(y);
dis[x] = dis[x] + dis[y];
return f[x];
}
int main() {
scanf("%d %d", &n, &m);
int ans = 0, x, y, z;
for (int i = 1; i <= n; i++) f[i] = i;
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &x, &y, &z);
int x1 = Find(x), y1 = Find(y);
if (x1 != y1) {
f[y1] = x1;
dis[y1] = dis[x] + z - dis[y];
} else if ((dis[x] + z) % MOD != dis[y] % MOD) ++ans;
}
printf("%d\n", ans);
return 0;
}