P2597 [ZJOI2012]灾难——拓扑,倍增,LCA

最近想学支配树,但是基础还是要打好了的;

P2597 [ZJOI2012]灾难

这道题是根据食物链链接出一个有向图的关系,求一个物种的灭绝会连带几种物种的灭绝;

求得就是一个点能支配几个点;

如果一个点没有食物了就会灭绝,那他的支配点就是他所有食物的LCA;

LCA死了,食物都死了,他也就死了;

我们先根据吃和被吃建图,连一条他和食物的有向边;

我们处理出拓扑序,入度为零的点就是终极捕食者;

重新建一个树,每个点支配的数量就是他为根的子树大小-1;

我们只需要将他和食物的LCA连边即可;这个时候我们连接的是反的,食物连向捕食者,这样子树大小才正确;

新加的虚拟节点没有影响,遍历树时很方便。

建立编号n+1的虚拟节点,将所有没有出边的光合食物连向这个点,以便以后求LCA;

注意每次都要更新f[][];

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=7e5+10;
int pre[maxn*2],last[maxn],other[maxn*2],l;
int pre2[maxn*2],last2[maxn],other2[maxn*2],l2;
int n;
void add(int x,int y)
{
    l++;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
}

void add2(int x,int y)
{
    l2++;
    pre2[l2]=last2[x];
    last2[x]=l2;
    other2[l2]=y;
}
queue<int> q;
int topo[maxn],sum,in_eage[maxn];
int dep[maxn],father[maxn];

int f[maxn][20];

void rmq(int x)
{
    f[x][0]=father[x];
    for(int i=1;i<=17;i++)
    {
        f[x][i]=f[f[x][i-1]][i-1];
    }
}

int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=0;i<=17;i++)
    {
        if((dep[x]-dep[y])&(1<<i)) x=f[x][i];
    }
    if(x==y) return x;
    for(int j=17;j>=0;j--)
    {
        if(f[x][j]!=f[y][j])
        {
            x=f[x][j];
            y=f[y][j];
        }
    }
    return f[x][0];
}

void toposort()
{
    for(int i=1;i<=n;i++)
    {
        if(in_eage[i]==0)
        {
            q.push(i);
        }
    }
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        topo[++sum]=x;
        for(int p=last[x];p;p=pre[p])
        {
            int v=other[p];
            in_eage[v]--;
            if(in_eage[v]==0)
            {
                q.push(v);
            }
        }
    }
}

void build()
{
    dep[n+1]=1;
    father[n+1]=n+1;
    for(int i=n;i>=1;i--)
    {
        int x=topo[i];
        if(last[x]==0)
        {
            dep[x]=2;
            father[x]=n+1;
            add2(n+1,x);
            f[x][0]=n+1;
            continue;
        }
        else
        {
            int lca=other[last[x]];
            for(int p=last[x];p;p=pre[p])
            {
                int v=other[p];
                lca=LCA(lca,v);
            }
            father[x]=lca;
            add2(lca,x);
            dep[x]=dep[lca]+1;
            rmq(x);
        }
    }
}
int siz[maxn];

void dfs(int x)
{
    siz[x]=1;
    for(int p=last2[x];p;p=pre2[p])
    {
        int v=other2[p];
        dfs(v);
        siz[x]+=siz[v];
    }    
}    

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        while(x)
        {
            in_eage[x]++;
            add(i,x);
            scanf("%d",&x);
        }
    }
    toposort();
    build();
    dfs(n+1);
    for(int i=1;i<=n;i++)
    {
        printf("%d\n",siz[i]-1);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WHFF521/p/11605746.html