原题:
n<=5e4,k<=1e5
自己想了半天,发现了只需要立即合并真话,无视假话,那么就可以把已知的真话处理成若干个三元环,而不存在错综复杂的关系
但是这样处理起来太难写,还不一定对
最后还是决定看题解,果然发现了新知识点。。。
分组并查集,给每个动物拆ABC三个点,相同字母的分一组
盗一个洛谷题解的图,作者id是sooke,原文地址:https://www.luogu.com.cn/blog/Sooke/solution-p2024
如果是吃的关系,就对A到B、B到C、C到A三种跨组关系都合并,如果是相等的关系,就三个组内合并
这样若组间的点位于同一集合,就说明存在吃的关系,如果组内的点位于同一集合,就说明存在相等的关系
两个动物的关系只有A吃B,B吃A,A等于B三种
若要判断某种关系是否存在,只需判断剩下两个关系是否存在,如果存在就表示冲突
如果三种关系都不存在就表示不知道
代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n,m; 5 int tp[151000]; 6 int ans=0; 7 int gttp(int x){ 8 int y=x,tmp; 9 for(;tp[y]!=y;y=tp[y]); 10 for(;x!=y;){ tmp=tp[x]; tp[x]=y; x=tmp;} 11 return y; 12 } 13 void mg(int x,int y){ tp[gttp(x)]=tp[gttp(y)];} 14 int main(){ 15 cin>>n>>m; 16 for(int i=1;i<=n*3;++i) tp[i]=i; 17 int mk,l,r; 18 while(m --> 0){ 19 scanf("%d%d%d",&mk,&l,&r); 20 if(l>n || r>n){ ++ans; continue;} 21 if(mk==2){ 22 if(gttp(l+n)==gttp(r)) ++ans; 23 else if(gttp(l)==gttp(r)) ++ans; 24 else if(gttp(l)!=gttp(r+n)){ 25 for(int i=0;i<3;++i) 26 mg(l+i*n,r+((i+1)%3)*n); 27 } 28 } 29 else{ 30 if(gttp(l+n)==gttp(r)) ++ans; 31 else if(gttp(l)==gttp(r+n)) ++ans; 32 else if(gttp(l)!=gttp(r)){ 33 for(int i=0;i<3;++i) 34 mg(l+i*n,r+i*n); 35 } 36 } 37 } 38 cout<<ans<<endl; 39 return 0; 40 }