题目大意
一个生态系统中有n种生物,它们形成了食物链和食物网。这n种生物中,一些是生产者,不需要吃其他生物就能生存;剩下的一些是消费者,必须吃其他的一些生物才能生存。
一种生物的重要性定义为,如果这种生物灭绝,将会导致包括自身在内的多少种生物灭绝。一种消费者生物,如果它的所有食物都灭绝,则这种生物也会灭绝。
一种生物的后效性定义为,如果这种生物灭绝,引发的灭绝事件将会持续多少个单位时间。一种消费者生物,如果它的最后一种食物在上个单位时间灭绝,则它会在当前这个单位时间灭绝。
现在的任务是计算每种生物的重要性和后效性。
第一行两个整数 n, m,表示生物的种类数和食物关系数量。
接下来m行,每行两个整数 ai, bi,表示第 ai 种生物可以以第 bi 种生物为食。保证不会出现任何一种生物直接或间接吃自己的情况,同一条关系保证不会重复出现。不吃其他任何生物的生物都是生产者。
输出 n 行,第 i 行两个整数 ci, di,分别是表示第 i 种生物的重要性和后效性。
样例数据
input:
6 7
2 1
3 1
4 2
4 3
5 4
6 4
6 5
output:
6 5
1 1
1 1
3 3
1 1
1 1
思路
我们知道假如一个物种灭绝,那么他的所有食物都已经灭绝了,否则他不可能灭绝。
而让他的食物都灭绝,那么他的所有食物的LCA或LCA的父亲一定要灭绝
这样我们就有思路了,先拓扑排序,按拓扑序将每个点挂在所有他食物的LCA下面
为什么要这么做呢?因为按拓扑序来处理到一个点的时候,他的所有食物一定已经被处
理完了,这时才好统计他食物的LCA
第二问呢?
对于每个节点,在拓扑排序时给每个节点记录一个dis。
第二问的答案就是i节点的子树中最大的dis,dfs时记录一下即可。
#include<stdio.h>
#include<bits/stdc++.h>
#define maxn 100005
#define maxm 100005
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int read()
{
char t=GC;
int x=0;
while(!isdigit(t)) t=GC;
while(isdigit(t)) x=x*10+t-48,t=GC;
return x;
}
using namespace std;
vector<int>son[maxn];
int n,m,res[maxn],dis[maxn],maxdis[maxn];
int cnt,ey[maxm*3],ne[maxm*3],elast[maxn];
inline void add_top_edge(int x,int y){
cnt++;
ey[cnt]=y;
ne[cnt]=elast[x];
elast[x]=cnt;
}
int tree_cnt,tree_ey[maxm*3],tree_ne[maxm*3],tree_elast[maxn];
inline void add_tree_edge(int x,int y){
tree_cnt++;
tree_ey[tree_cnt]=y;
tree_ne[tree_cnt]=tree_elast[x];
tree_elast[x]=tree_cnt;
}
int tot,degree[maxn],Top[maxn],f[maxn][20];
inline void Jump(int x){
int s=ceil(log2(n));
for(int i=1;i<=s;++i){
f[x][i]=f[f[x][i-1]][i-1];
if(!f[x][i]) break;
}
}
inline void go_up(int &p,int x){
int s=ceil(log2(n));
for(int i=0;i<=s;i++){
if(x&1<<i){
p=f[p][i];
}
}
return;
}
int depth[maxn];
int lca(int u,int v){
if(depth[u]<depth[v]) swap(u,v);
go_up(u,depth[u]-depth[v]);
if(u==v) return u;
int s=ceil(log2(n));
for(int i=s;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
inline void top(){
queue<int>Q;
for(int i=1;i<=n;i++){
if(!degree[i]){
Q.push(i);
son[i].push_back(0);
dis[i]=1;
}
}
while(!Q.empty()){
int temp=Q.front();
Top[++tot]=temp;
Q.pop();
for(int i=elast[temp];i;i=ne[i]){
int v=ey[i];
dis[v]=max(dis[v],dis[temp]+1);
degree[v]--;
if(!degree[v]){
Q.push(v);
}
}
}
}
inline void Build_tree(){
for(int i=1;i<=tot;i++){
int now=Top[i];
int fa=son[now][son[now].size()-1];
for(int j=0;j<son[now].size()-1;j++){
fa=lca(fa,son[now][j]);
}
add_tree_edge(fa,now);
add_tree_edge(now,fa);
depth[now]=depth[fa]+1;
f[now][0]=fa;
Jump(now);
}
}
int Ans[maxn];
inline void dfs(int u,int fa){
Ans[u]=1;
maxdis[u]=dis[u];
for(int i=tree_elast[u];i;i=tree_ne[i]){
int v=tree_ey[i];
if(v!=fa){
dfs(v,u);
Ans[u]+=Ans[v];
maxdis[u]=max(maxdis[v],maxdis[u]);
}
}
res[u]=maxdis[u]-dis[u]+1;
return;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u,v;
u=read(),v=read();
son[u].push_back(v);
add_top_edge(v,u);
degree[u]++;
}
top();
depth[0]=1;
Build_tree();
Ans[n+1]=1;
dfs(0,n+1);
for(int i=1;i<=n;i++){
printf("%d %d\n",Ans[i],res[i]);
}
return 0;
}