刚开始看这道题,总感觉可以对这些动物进行染色,令颜色相同的为一类。但是这样是有漏洞的。当你遇到一个没有染过色的动物,你需要给它染什么颜色呢?不能保证结果是正确的。
这道题目考查的数据结构是并查集。
用father[n],path[n]数组分别记录当前结点的祖先和到祖先的距离。
这里规定距离为0时为同类,为1时表示被祖先吃,为2时表示吃祖先。
初始时每个元素的祖先是自己,距离为0。
对于每一句话,首先判断是x,y是否大于n,是否出现自己吃自己的情况,满足时讨论如下两种情况。
- 如果d=1,表示读入的x和y是同类,这时分别找到x,y和祖先fx,fy,如果fx=fy,说明他们是同一祖先。这时判断x和y到祖先的距离是否相等,显然,不相等证明这是一句假话。如果fx<>fy,说明x和y不在同一集合中,此时将这两个集合合并。合并时可以通过一个简单的向量关系算出fx->fy的距离,即path[fx]=path[y]-path[x].
- 如果d=2,表示x吃y,同样的找到它们的祖先,若fx=fy,则根据向量关系判断它们的距离是否矛盾,即检查path[x]-path[y]-2是否为0。若fx<>fy,则类似地根据已有的向量关系算出fx->fy的距离,即 path[fx]=path[y]-path[x]+2.
注意的地方是,因为path在运算过程可能出现负数,为避免这一情况且保证path的性质,可以在每次对path运算后加三再对三取模。
*path数组在维护时要注意,建立新关系时,直接把fx指向fy,相应地修改path值即可,对儿子结点的维护放在getfather函数中进行。
VAR
FA,D:ARRAY[1..500000]OF LONGINT;
N,K,DD,X,Y,I,ANS,P,Q:LONGINT;
FUNCTION FIND(X:LONGINT):LONGINT;
BEGIN
IF FA[X]=0 THEN EXIT(X);
FIND:=FIND(FA[X]);
D[X]:=(D[X]+D[FA[X]])MOD 3;
FA[X]:=FIND;
END;
BEGIN
READLN(N,K);
FILLCHAR(FA,SIZEOF(FA),0);
ANS:=0;
FOR I:=1 TO K DO
BEGIN
READLN(DD,X,Y);
IF (X>N) OR (Y>N) THEN
BEGIN
INC(ANS);
CONTINUE;
END;
P:=FIND(X);
Q:=FIND(Y);
IF DD=1 THEN
BEGIN
IF P=Q THEN
BEGIN
IF D[X]<>D[Y] THEN
BEGIN
INC(ANS);
CONTINUE;
END;
END
ELSE
BEGIN
FA[P]:=Q;
D[P]:=(D[Y]-D[X]+3) MOD 3;
END;
END
ELSE
BEGIN
IF P=Q THEN
BEGIN
IF (2-D[X]+D[Y]) MOD 3<>0 THEN
BEGIN
INC(ANS);
CONTINUE;
END;
END
ELSE
BEGIN
FA[P]:=Q;
D[P]:=(D[Y]-D[X]+2) MOD 3;
END;
END;
END;
WRITELN(ANS);
END.
本博客部分引用CSDN MForever大牛博客内容。