传送门:bzoj2815
支配树模板
题解
先拓扑排序,建立灭绝树,对于该树,满足如下定义:
对于树中的每个节点,若该节点的生物灭绝,那么以它为跟的子树内的所有节点的生物都会跟着灭绝。
按拓扑序倒序加入“灭绝树”,建的时候连在所有它的食物点的lca下即可(lca灭绝代表,所有它可以吃的都灭绝了)。
代码
#include<bits/stdc++.h>
#define gc getchar()
#define pb push_back
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],f[N][21],dep[N],id[N];
vector<int>g[N];
char cp;
inline void rd(int &x)
{
cp=gc;x=0;int f=0;
for(;!isdigit(cp);cp=gc) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc) x=x*10+(cp^48);
if(f) x=-x;
}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;in[v]++;}
inline int LCA(int x,int y)
{
if(x==-1) return y;
if(dep[x]<dep[y]) swap(x,y);
int i,dlt=dep[x]-dep[y];
for(i=0;bin[i]<=dlt;i++) if(bin[i]&dlt)
x=f[x][i];
if(x==y) return x;
for(i=20;i>=0;--i)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
void dfs(int x)
{
int i,j;
for(i=g[x].size()-1;i>=0;--i){
j=g[x][i];dfs(j);
sz[x]+=(sz[j]+1);
}
}
queue<int>que;
int main(){
int i,j,x,y,z;
bin[0]=1;for(i=1;i<=21;i++) bin[i]=bin[i-1]<<1;
rd(n);
for(i=1;i<=n;i++)
for(rd(x);x;rd(x)) lk(i,x);
for(i=1;i<=n;i++) if(!in[i]) que.push(i);
for(;!que.empty();){
x=que.front();que.pop();id[++cnt]=x;
for(i=head[x];i;i=nxt[i]){
j=to[i];in[j]--;if(!in[j]) que.push(j);
}
}
for(j=cnt;j>0;--j){
x=id[j];y=-1;//注意y一定要设成-1 而不是0,因为0也是灭绝树上的点
for(i=head[x];i;i=nxt[i]) y=LCA(y,to[i]);
if(y==-1) y=0;g[y].pb(x);dep[x]=dep[y]+1;f[x][0]=y;
for(i=1;bin[i]<=dep[x];++i) f[x][i]=f[f[x][i-1]][i-1];
}
dfs(0);
for(i=1;i<=n;++i) printf("%d\n",sz[i]);
return 0;
}