【[ZJOI2012]灾难】

好像很久之前就看过这道题,大概是刚学\(LCA\)的时候

之后当时肯定是不会的呀

现在发现这道题并不是非常难

首先我们发现这个灭绝的关系非常像一棵树,我们建出这个灭绝树求一个前缀和就可以啦

那么应该怎么建这棵树呢

我们一边拓扑排序一边建树,一个点的父亲应该是其所有食物节点的\(lca\),于是一边拓扑排序一边求\(lca\)就好了

手滑了好几次

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define re register
#define maxn 70005
struct Edge
{
    int v,nxt;
}e[200005];
int head[maxn];
int num,n;
inline void add_edge(int x,int y)
{
    e[++num].v=y;
    e[num].nxt=head[x];
    head[x]=num;
}
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
int deep[maxn],f[maxn][18];
namespace Topsort
{
    struct E
    {
        int v,nxt;
    }e[200005];
    int num,head[maxn],r[maxn],q[maxn];
    int fa[maxn];
    inline void add(int x,int y)
    {
        e[++num].v=y;
        e[num].nxt=head[x];
        head[x]=num;
    }
    inline int LCA(int x,int y)
    {
        if(deep[x]<deep[y]) std::swap(x,y);
        for(re int i=17;i>=0;--i)
        if(f[x][i]!=-1&&deep[f[x][i]]>=deep[y]) x=f[x][i];
        if(x==y) return x;
        for(re int i=17;i>=0;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    inline void init()
    {
        n=read();
        int x;
        for(re int i=1;i<=n;i++)
        {
            x=read();
            while(x) add(x,i),r[i]++,x=read();
        }
        for(re int i=1;i<=n;i++)
        if(!r[i]) add(0,i),r[i]++;
        int tot=0;
        q[++tot]=0;
        memset(f,-1,sizeof(f));
        memset(fa,-1,sizeof(fa));
        for(re int i=1;i<=tot;i++)
        {
            for(re int j=head[q[i]];j;j=e[j].nxt)
            {
                r[e[j].v]--;
                if(fa[e[j].v]==-1) fa[e[j].v]=q[i];
                else fa[e[j].v]=LCA(fa[e[j].v],q[i]);
                if(!r[e[j].v])
                {
                    add_edge(fa[e[j].v],e[j].v);
                    deep[e[j].v]=deep[fa[e[j].v]]+1;
                    f[e[j].v][0]=fa[e[j].v];
                    for(re int k=1;k<=17;k++)
                        f[e[j].v][k]=f[f[e[j].v][k-1]][k-1];
                    q[++tot]=e[j].v;
                }
            }
        }
    }
}
int sz[maxn];
void dfs(int x)
{
    sz[x]=1;
    for(re int i=head[x];i;i=e[i].nxt)
    if(deep[e[i].v]>deep[x])
    {
        deep[e[i].v]=deep[x]+1;
        dfs(e[i].v);
        sz[x]+=sz[e[i].v];
    }
}
int main()
{
    Topsort::init();
    dfs(0);
    for(re int i=1;i<=n;i++)
        printf("%d\n",sz[i]-1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10205742.html