AGC016E Poor Turkeys

Link
对于每一只火鸡,我们维护一个集合表示为了让这只火鸡活下来,有哪些火鸡会被拉去垫背。
具体来说我们先将它自己加入集合,然后倒序遍历每一个人,如果这个人要吃的火鸡中有一个在集合中,那么我们就把另一个也加入这个集合;如果这个人要吃的火鸡都在集合中,那么这只火鸡就一定无法存活到最后。
然后我们枚举两只火鸡,如果这两只火鸡都有可能存活到最后,并且对应的集合无交,那么这两只火鸡就是可以一同活到最后的,否则一定无法一同活到最后。

#include<bitset>
#include<cctype>
#include<cstdio>
const int N=100007,M=407;
int a[N],b[N],d[N];std::bitset<M>f[M];
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int main()
{
    int n=read(),m=read(),ans=0;
    for(int i=1;i<=m;++i) a[i]=read(),b[i]=read();
    for(int i=1,j;i<=n;++i)
	for(f[i][i]=1,j=m;j;--j)
	{
	    if(f[i][a[j]]&&f[i][b[j]]) {d[i]=1;break;}
	    if(f[i][a[j]]&&!f[i][b[j]]) f[i][b[j]]=1;
	    else if(!f[i][a[j]]&&f[i][b[j]]) f[i][a[j]]=1;
	}
    for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(!d[i]&&!d[j]&&(f[i]&f[j]).none()) ++ans;
    printf("%d",ans);
}