维护具有多重关系的集合(扩展域)
总结
首先这个题AC了部分,让我很难受
用了四个OJ测试,就SCU过不了,我就不知道为什么,是我的程序有BUG,还是他的数据有问题,如果我的代码有问题,极力欢迎纠正。
这个题好像有两个写法,一个是本题的写法,一个边带权写法。
解析
fat[N*3],这里会开辟三个域,一个指自己本身,一个作为天敌状态,一个作为食物状态。
然后就是模拟完事吧。
补充
之前我一直有一个迷惑,一棵树里的关系到底维护什么?
每一个结点都有三个状态,也是我们创建的三个域
以前的想法
[1,n]一定为自己
[n+1,2n]一定为食物
[2n+1,3*n]一定为天敌
后来的想法
一棵树中数据[1,n]的所有数字同类,暂且为a类,数据[n+1,2n]的所有数字为同类,暂且为b类,数据[2n+1,3*n]的所有数字为同类,暂且为c类,然后关系一定满足a吃b吃c吃a,维护的就是这个关系。
关系再准确一点就是
情况一
Xa吃Yb吃Zc吃Xa
情况二
Xb吃Yc吃Za吃Xb
情况三
Xc吃Ya吃Zb吃Xc
每次合并三种类型,也就维护了三种状态了。
每一颗树中,某一个集合中a类,b类,c类就很明显看到动物X与动物Y之间存在什么关系!
如果X与Y关系在某一个集合与之前的关系不矛盾,那就建立关系(任意一个集合都能看出关系,一定的)
如果矛盾,那就ans++
扫描二维码关注公众号,回复:
9347240 查看本文章
const int N=5e4+5;
int fat[N*3];
int find(int x)
{
return fat[x]==x?x:fat[x]=find(fat[x]);
}
signed main()
{
IOS;
file();
int n,m,ans=0;
cin>>n>>m;
for(int i=1;i<=n*3;i++)
fat[i]=i;
while(m--)
{
int flag,a,b;
cin>>flag>>a>>b;
if(a>n||b>n)
{
ans++;
continue;
}
///a1吃a2吃a3吃a1
int a1=find(a),a2=find(a+n),a3=find(a+2*n);
int b1=find(b),b2=find(b+n),b3=find(b+2*n);
if(flag==1)
{
if(a1==b2||b1==a2)///判断a和b是否具有捕食关系
ans++;
else
{
fat[a1]=b1;
fat[a2]=b2;
fat[a3]=b3;
}
}
else
{
if(a1!=b1&&b1!=a2)///判断a和b不是同类且b不吃a
{
fat[a1]=b2;
fat[a2]=b3;
fat[a3]=b1;
}
else
ans++;
}
}
cout<<ans<<endl;
return 0;
}