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;
}

原文地址:https://www.cnblogs.com/WHFF521/p/11605746.html

时间: 2024-11-09 04:28:40

P2597 [ZJOI2012]灾难——拓扑,倍增,LCA的相关文章

P2597 [ZJOI2012]灾难 拓扑排序

这个题有点意思,正常写法肯定会T,然后需要优化.先用拓扑排序重构一遍树,然后进行一个非常神奇的操作:把每个点放在他的食物的lca上,然后计算的时候直接dfs全加上就行了.为什么呢,因为假如你的食物的lca死了,你就很自然的死了.这个题还要加一个超级源点,一开始我没加只拿了20分.但是不知道为什么,后来想到有可能一个兄弟能吃两个生产者,在查询lca的时候会跪...剩下就没啥了,顺便练一下倍增求lca. 题干: 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们

【bzoj2815】[ZJOI2012]灾难 拓扑排序+构造+倍增LCA

题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统.如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难. 我们现在从专业一点的角度来看这个问题.我们用一种叫做食物网的有向图来描述生物之间的关系: 一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个

BZOJ 2815 ZJOI 2012 灾难 动态倍增LCA

题目背景 阿米巴是小强的好朋友. 题目大意 给出一个食物链(拓扑图),定义一个生物所有的食物都灭绝了之后他自己也灭绝了.定义每种生物灭绝之后跟随着它灭绝的生物个数为这个生物的灾难值.求所有生物的灾难值. 思路 看题帽知出题人系列. fhq的题大家也知道,一般都是不可做的.于是我就去看了他的题解,发现这个题还是可做的. 定义一种灭绝树,对于任意一个子树,若这个子树的根节点灭绝,那么子树中的所有点都会灭绝.只要弄出这个树,我们就可以解决问题了. 先加一个超级食物,然后从这个点开始拓扑排序,保证处理到

P2597 [ZJOI2012]灾难(lca)

题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统.如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难. 我们现在从专业一点的角度来看这个问题.我们用一种叫做食物网的有向图来描述生物之间的关系: 一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边.

【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815 原版题解:http://fanhq666.blog.163.com/blog/static/8194342620124274154996/ 首先这个生态系统里可能有多个生产者,所以我们可以让生产者吃一种构造出来的食物——阳光. 这道题的图没有环(不然还怎么叫食物网),所以我们可以用拓扑排序把从阳光到各级消费者的先后顺序求出来. 我们可以建出一个结构(可以证明这个结构是一棵树),生

[bzoj2815] [洛谷P2597] [ZJOI2012] 灾难

Description 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统.如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难. 我们现在从专业一点的角度来看这个问题.我们用一种叫做食物网的有向图来描述生物之间的关系: 一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连

Luogu P2597 [ZJOI2012]灾难

一道非常综合的好题然后就莫名其妙地知道了动态LCA的求法 果然是ZJOI的题目,只能说这思路服了 首先我们发现每次操作只会灭绝一种动物,然后我们想一下就知道如果有\(n(n>=2)\)个食物的动物就不会灭绝. 然后我们YY一个叫灭绝树的东西,在这个树上的点都满足一个性质:当一个节点被割去时,以它为根的整棵子树对应的动物都会灭亡. 然后我们只需要考虑如何搞出这个树了. 然后我们再YY一个虚拟节点0,让它向所有生产者连边,我们可以形象得理解成太阳. 然后我们将题目中的树反向建边,然后就变成了这样:

【BZOJ2815】【ZJOI2012】灾难 阿米巴和小强题 动态倍增LCA 灾难树

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44104163"); } 题意: 原题面请见JSShining博客 http://www.cnblogs.com/JS-Shining/archive/2013/01/12/2857429.html 题解: 我们构建一颗灾难树,使得一

【BZOJ2815】[ZJOI2012]灾难 拓补排序+LCA

[BZOJ2815][ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统.如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难. 我们现在从专业一点的角度来看这个问题.我们用一种叫做食物网的有向图来描述生物之间的关系: 一个食物网有N个点,代表N种生物,如果生物