首页 > 技术文章 > 【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)

quzhizhou 2017-12-06 18:01 原文

  题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815

  原版题解:http://fanhq666.blog.163.com/blog/static/8194342620124274154996/

  首先这个生态系统里可能有多个生产者,所以我们可以让生产者吃一种构造出来的食物——阳光。

  这道题的图没有环(不然还怎么叫食物网),所以我们可以用拓扑排序把从阳光到各级消费者的先后顺序求出来。

  我们可以建出一个结构(可以证明这个结构是一棵树),生物x会因为生物y的灭绝而灭绝,当且仅当y是x的祖先。

  因此,如果一种生物会灭绝,只能是因为它的所有食物的lca灭绝了,否则至少有一种食物不会灭绝,这种生物也能活下去,所以这种生物在树上的位置就是它所有食物的lca的孩子。

  然后我们把树建出来之后每个节点的答案就是以他为根的子树的节点个数-1。

  代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
ll read()
{
    ll tmp=0; char f=1,c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1; c=getchar();}
    while('0'<=c&&c<='9'){tmp=tmp*10+c-'0'; c=getchar();}
    return tmp*f;
}
using namespace std;
int fir[70010]={0},ne[1000010],to[1000010],x[1000010],y[1000010];
int q[70010],vis[70010]={0};
ll in[70010]={0},cnt[70010];
int fa[70010][20],dep[70010];
int n,m,tot=0;
void add(int x,int y){to[++tot]=y; ne[tot]=fir[x]; fir[x]=tot;}
int lca(int x,int y)
{
    int i;
    if(dep[x]<dep[y]){int tmp=x; x=y; y=tmp;}
    for(i=(int)(log(n)/log(2)+1);i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i];
    if(x==y)return x;
    for(i=(int)(log(n)/log(2)+1);i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
    int i,j;
    n=read();
    for(i=1;i<=n;i++){
        int k=read();
        if(!k)add(0,i),in[i]=1,x[tot]=i,y[tot]=0;
        while(k){++in[i]; add(k,i); x[tot]=i; y[tot]=k; k=read();}
    }
    int h=0,t=0; q[0]=0; vis[0]=1;
    while(h<=t){
        for(i=fir[q[h]];i;i=ne[i]){
            --in[to[i]];
            if(!in[to[i]])q[++t]=to[i],in[to[i]]=1<<30;
        }
        ++h;
    }
    m=tot; tot=0;
    for(i=1;i<=n;i++)fir[i]=0;
    for(i=1;i<=m;i++)add(x[i],y[i]);
    for(i=0;i<=n;i++)
        for(j=0;1<<j<=n;j++)
            fa[i][j]=-1;
    fa[0][0]=-1; dep[0]=0;
    for(i=1;i<=n;i++){
        int p=-1;
        for(j=fir[q[i]];j;j=ne[j])
            if(p==-1)p=to[j];else p=lca(p,to[j]);
        fa[q[i]][0]=p; dep[q[i]]=dep[p]+1;
        for(j=1;1<<j<=n&&fa[fa[q[i]][j-1]][j-1]>=0;j++)fa[q[i]][j]=fa[fa[q[i]][j-1]][j-1];
    }
    for(i=1;i<=n;i++)cnt[i]=1;
    for(i=n;i;i--)cnt[fa[q[i]][0]]+=cnt[q[i]];
    for(i=1;i<=n;i++)
        printf("%lld\n",cnt[i]-1);
}
bozj2815

 

推荐阅读