BZOJ 2815 ZJOI 2012 灾难 动态倍增LCA

题目背景

阿米巴是小强的好朋友。

题目大意

给出一个食物链(拓扑图),定义一个生物所有的食物都灭绝了之后他自己也灭绝了。定义每种生物灭绝之后跟随着它灭绝的生物个数为这个生物的灾难值。求所有生物的灾难值。

思路

看题帽知出题人系列。
fhq的题大家也知道,一般都是不可做的。于是我就去看了他的题解,发现这个题还是可做的。
定义一种灭绝树,对于任意一个子树,若这个子树的根节点灭绝,那么子树中的所有点都会灭绝。只要弄出这个树,我们就可以解决问题了。
先加一个超级食物,然后从这个点开始拓扑排序,保证处理到的每个点的的食物肯定被处理过。假设我们处理到一个节点的时候,拓扑序之前的所有点已经建立好了一颗灾难树,我们只需要考虑的是将当前节点放在灾难树的什么位置。由题意得,一个点的所有食物全部灭绝这个点就会灭绝,因此我们只需要找到这个点的所有食物节点的LCA,只要LCA灭绝了,那么这个点就会灭绝。
之后随便yy一下怎么维护动态倍增LCA就行了。

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
using namespace std;

int points;
int head[MAX],total;
int _next[MAX],aim[MAX];
vector<int> food[MAX];

inline void Add(int x,int y)
{
    _next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}

int _in[MAX];
queue<int> q;

int deep[MAX];
int father[MAX][20];

inline int GetLCA(int x,int y)
{
    if(deep[x] < deep[y])   swap(x,y);
    for(int i = 19; ~i; --i)
        if(deep[father[x][i]] >= deep[y])
            x = father[x][i];
    if(x == y)  return x;
    for(int i = 19; ~i; --i)
        if(father[x][i] != father[y][i])
            x = father[x][i],y = father[y][i];
    return father[x][0];
}

namespace Graph{
    int head[MAX],total;
    int _next[MAX],aim[MAX];

    int ans[MAX];

    void Add(int x,int y) {
        _next[++total] = head[x];
        aim[total] = y;
        head[x] = total;
    }
    void DFS(int x) {
        ans[x] = 1;
        for(int i = head[x]; i; i = _next[i]) {
            DFS(aim[i]);
            ans[x] += ans[aim[i]];
        }
    }
}

int main()
{
    cin >> points;
    for(int x,i = 1; i <= points; ++i)
        while(scanf("%d",&x),x) {
            Add(x,i);
            ++_in[i];
            food[i].push_back(x);
        }
    for(int i = 1; i <= points; ++i)
        if(!_in[i]) {
            Add(0,i);
            ++_in[i];
            food[i].push_back(0);
        }
    q.push(0);
    deep[0] = 1;
    while(!q.empty()) {
        int x = q.front(); q.pop();
        if(x) {
            int lca = *food[x].begin();
            for(vector<int>::iterator it = food[x].begin(); it != food[x].end(); ++it)
                lca = GetLCA(lca,*it);
            deep[x] = deep[lca] + 1;
            father[x][0] = lca;
            for(int i = 1; i <= 19; ++i)
                father[x][i] = father[father[x][i - 1]][i - 1];
            Graph::Add(lca,x);
        }
        for(int i = head[x]; i; i = _next[i])
            if(!--_in[aim[i]])
                q.push(aim[i]);
    }
    Graph::DFS(0);
    for(int i = 1; i <= points; ++i)
        printf("%d\n",Graph::ans[i] - 1);
    return 0;
}

你可能感兴趣的:(LCA,bzoj,fhq,Zjoi2012,灾难树)