NOI2001 食物链
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是“1 X Y”,表示X和Y是同类。
第二种说法是“2 X Y”,表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1<=N<=50,000)和K句话(0<=K<=100,000),输出假话的总数。
题解:
非法的情况有三种,后两种很明显容易处理,读入的时候判断即可。
第一种情况是处理集合之间是否冲突的问题,容易想到用并查集。
对于第一种,我们分两种情况讨论。我们将N个点做2个虚构投影,即将fa数组扩大为3*n。
fa[1~n]被fa[n+1~2n]吃 fa[n+1~2n]被fa[2n+1~3n]吃 fa[2n+1~3n] 被 fa[1~n] 吃
当d=1时
因为是合并,只需要判断 x是否被y吃、y是否被x吃( find(x+n)=find(y) find(x+2n)=fa(y) )
若合法,将 (x,y) (x+n,y+n) (x+2n,y*2n) 合并;不合法则ans+1
当d=2时
判断 x是否被y吃(find(x+2n)=find(y)) 或 x和y是否同类 (find(x)=find(y))
若合法,将(x+n,y) (x+2n,y+n) (x,y+2n)合并 不合法则inc(ans);
const
maxn=50001;
var
n,k,i,d,x,y,ans:longint;
fa:array[1..maxn*3]of longint;
f:boolean;
function find(x:longint):longint;
begin
if fa[x]=x then exit(x);
fa[x]:=find(fa[x]);
find:=fa[x];
end;
procedure union(x,y:longint);
var
u,v:longint;
begin
u:=find(x);v:=find(y);
if u<>v then
fa[u]:=v;
end;
procedure init;
var
i:longint;
begin
readln(n,k);
for i:=1 to 3*n do
fa[i]:=i;
end;
begin
// assign(input,'data3.in');reset(input);
init;
for i:=1 to k do
begin
readln(d,x,y);
if (d=2)and(x=y) then
begin
inc(ans);
continue;
end;
if (x>n)or(y>n) then
begin
inc(ans);
continue;
end;
if d=1 then
begin
f:=false;
if find(x+n)=find(y) then f:=true;
if find(x+2*n)=find(y) then f:=true;
if f=false then
begin
union(x,y);
union(x+n,y+n);
union(x+2*n,y+2*n);
end
else inc(ans);
end;
if d=2 then
begin
f:=false;
if find(x)=find(y) then f:=true;
if find(x+2*n)=find(y) then f:=true;
if f=false then
begin
union(x+n,y);
union(x,y+n+n);
union(x+n+n,y+n);
end
else inc(ans);
end;
end;
writeln(ans);
end.