NOI2001 食物链
刚开始看这道题,总感觉可以对这些动物进行染色,令颜色相同的为一类。但是这样是有漏洞的。当你遇到一个没有染过色的动物,你需要给它染什么颜色呢?不能保证结果是正确的。
这道题目考查的数据结构是并查集。
用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大牛博客内容。