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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章