【BZOJ】 [ZJOI2012]灾难-DP

传送门:bzoj2815


题解

虽然此题tag是dp…
先拓扑排序一波,然后建立一颗名为“灭绝树”的树,对于该树,满足如下定义:
对于树中的每个节点,若该节点的生物灭绝,那么以它为跟的子树内的所有节点的生物都会跟着灭绝。
按拓扑序倒序加入“灭绝树”(仔细读一下题,你就会发现拓扑序大的才是王者),建的时候连在所有它的食物点的lca下就好了(lca灭绝代表,所有它可以吃的都灭绝了)。


代码

#include<bits/stdc++.h>
#define gc getchar()
using namespace std;

const int N=1e5+10;
int in[N],head[N],to[N],nxt[N],tot,sz[N];
int n,cnt,bin[22],tp[N],f[N][21],d[N];
vector<int>g[N];
vector<int>fir;

inline int rd()
{
    char ch=gc;int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=gc;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
    return x*f;
}

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;in[v]++;}

inline void dfs(int x)
{
    for(int i=g[x].size()-1;i>=0;i--){
        if(g[x][i]==f[x][0]) continue;
        f[g[x][i]][0]=x;
        dfs(g[x][i]);
        sz[x]+=(sz[g[x][i]]+1);
    }
}

inline int LCA(int x,int y)
{
    if(x==-1) return y;
    if(d[x]<d[y]) {int t=x;x=y;y=t;}
    int t=d[x]-d[y];
    for(int i=0;bin[i]<=t;i++){
        if(bin[i]&t) x=f[x][i];
    }
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i])
          x=f[x][i],y=f[y][i];
    }
    if(x!=y) return f[x][0];
    else return x;
}

int main(){
    bin[0]=1;for(int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
    n=rd();
    for(int x,i=1;i<=n;i++){x=rd();while(x!=0){lk(i,x);x=rd();}}
    for(int i=1;i<=n;i++) if(in[i]==0) fir.push_back(i);
    while(!fir.empty()){
        int e=fir.back();
        fir.pop_back();
        tp[++cnt]=e;
        for(int j=head[e];j;j=nxt[j]){
            in[to[j]]--;
            if(in[to[j]]==0) fir.push_back(to[j]);
        }
    }
    for(int i=cnt;i;i--){
        int e=tp[i],lca=-1;
        for(int j=head[e];j;j=nxt[j]) lca=LCA(lca,to[j]);
        if(lca==-1) lca=0;
        g[lca].push_back(e);
        d[e]=d[lca]+1;f[e][0]=lca;
        for(int j=1;bin[j]<=d[e];j++){
          f[e][j]=f[f[e][j-1]][j-1];
        }
    }
    dfs(0);
    for(int i=1;i<=n;i++) printf("%d\n",sz[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80294222