2019 11/12 div2 卡常大赛 T3 生物 题解


题目大意

一个生态系统中有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值