拓扑排序–>传递闭包
我们要知道所有牛的排名,就需要知道所有牛的相对排名,所以一共是n*(n-1)/2对,但是会有这样一些条件不需要知道:1>2,2>3,所以1>3所以第三对条件是不需要再找到一遍的,所以我们只需要找出这些不需要找的,用总数减去m再减去这些不需要的,就是最后结果
怎么求这些条件呢?不难发现,这玩意符合传递闭包,不存在环,所以我们可以反向建图,反向更新条件关系,然后最后统计答案就好了
例子
原顺序是1->2 1->3 2->4 3->5
那么反向建图之后依次向上更新,就可以得到每个点都能到达哪些点了
代码
//By AcerMo
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=10050;
int n,m;
int in[M],f[M/10][M/10];
int to[M],nxt[M],head[M],cnt;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y)
{
to[++cnt]=y;in[y]++;nxt[cnt]=head[x];head[x]=cnt;
return ;
}
inline void tops()
{
queue<int>q;
for (int i=1;i<=n;i++)
if (!in[i]) q.push(i);
while (q.size())
{
int u=q.front();q.pop();
for (int i=head[u];i;i=nxt[i])
{
in[to[i]]--;f[to[i]][u]|=1;
for (int k=1;k<=n;k++)
f[to[i]][k]|=f[u][k];
if (!in[to[i]]) q.push(to[i]);
}
}
return ;
}
signed main()
{
n=read();m=read();int x,y;
for (int i=1;i<=m;i++)
x=read(),y=read(),add(y,x);
tops();int ans=(n-1)*n/2;
for (int i=1;i<=n;i++)
for (int k=1;k<=n;k++)
ans-=f[i][k];
cout<<ans;
return 0;
}