BZOJ_2815_[ZJOI2012]灾难 倍增lca + 构造

BZOJ_2815_[ZJOI2012]灾难 倍增lca + 构造

题意:

我们用一种叫做食物网的有向图来描述生物之间的关系:一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。这个图没有环。图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。如果某个消费者的所有食物都灭绝了,它会跟着灭绝。我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。

给定一个食物网,你要求出每个生物的灾难值。

 

分析:

按照图中给出的图的拓扑序插点,对于每个点,让能吃它的所有点的lca作为它的父亲

统计一下子树大小就是答案

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 700000

int head[N],to[N<<1],nxt[N<<1],cnt;
int n,m,c[N],Q[N],l,r,f[N][21],dep[N];
int pos[N],siz[N];
int too[N],nxtt[N],headd[N];

inline void add(int u,int v){
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}

inline void adda(int u,int v){
    too[++cnt]=v;nxtt[cnt]=headd[u];headd[u]=cnt;
}

int lca(int x,int y){
    int i;
    if(dep[x]<dep[y])swap(x,y);
    for(i=20;i>=0;i--){
        if(dep[f[x][i]]>=dep[y])x=f[x][i];
    }
    if(x==y)return x;
    for(i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}

void dfs(int x,int y){
    siz[x]=1;
    int i;

    for(i=head[x];i;i=nxt[i]){
        if(to[i]!=y){
            dfs(to[i],x);
            siz[x]+=siz[to[i]];
        }
    }
}

int main(){
    scanf("%d",&n);

    int i,j,x;

    for(i=1;i<=n;i++){
        for(scanf("%d",&x);x;scanf("%d",&x)){
            adda(x,i);c[i]++;
        }
    }

    cnt=0;

    dep[n+1]=1;
    for(i=1;i<=n;i++){
        if(!c[i]){
            Q[r++]=i;
            dep[i]=1;
            add(i,n+1);
            add(n+1,i);
            dep[i]=2;
            f[i][0]=n+1;
            for(j=1;j<=20;j++){
                f[i][j]=f[f[i][j-1]][j-1];
            }
        }
    }
    while(l<r){
        x=Q[l++];

        for(i=headd[x];i;i=nxtt[i]){
            c[too[i]]--;
            if(!pos[too[i]]){
                pos[too[i]]=x;
            }else{
                pos[too[i]]=lca(pos[too[i]],x);
            }
            if(!c[too[i]]){
                add(too[i],pos[too[i]]);
                add(pos[too[i]],too[i]);
                dep[too[i]]=dep[pos[too[i]]]+1;
                f[too[i]][0]=pos[too[i]];
                
                for(j=1;j<=20;j++){
                    f[too[i]][j]=f[f[too[i]][j-1]][j-1];
                }

                Q[r++]=too[i];
            }
        }
    }

    //printf("%d\n",root);
    //for(i=1;i<=n;i++)if(dep[i]==1)dfs(i,0);
    dfs(n+1,0); 

    for(i=1;i<=n;i++){
        printf("%d\n",siz[i]-1);
    }
}

 

posted @ 2018-03-08 11:17  fcwww  阅读(163)  评论(0编辑  收藏  举报