[zjoi2012]灾难——拓扑排序+灭绝树
题目大意:
草原中有一张食物网,如果将一种动物弄死,将会有一些动物没有食物而死亡,那么称死亡动物的种类数为这种动物的灾难值。
求每一种动物的灾难值。
\(n\leq 65534\),输入数据\(\leq\) 10M。
思路:
题目可以转化为将DAG删除一个结点后有多少个结点变得不可达
不难发现,整张食物网其实是构成了一个树形结构,即直接导致某种动物死亡的动物有且只有一种。某一个结点的死亡必定会导致它的子树内的所有的动物都死亡。
于是我们尝试将这颗“灭绝树”给建出来,一种动物v要死亡,那么直接连向它的所有结点\(u_1,u_2,u_3\dots\)都必须要死亡。那么我们只要找到第一个可以使{u}全部死亡的结点,它就是v的父亲。
{u}必须在v之前处理出来,并且加入灭绝树中,于是直接按照拓扑序建树。之后的找父亲就是一个求lca的过程,只需要每次更新新结点的st表即可。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj2815.in","r",stdin);
freopen("bzoj2815.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=65534+10;
const int maxm=2e6+10;
int n,rt,deg[maxn],st[maxn][21],dep[maxn],Log[maxn],sz[maxn];
int beg[maxn],to[maxm<<1],las[maxm<<1],cnte=1;
vector<int>T[maxn],from[maxn];
void add(int u,int v){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
}
void init(){
read(n);
rt=n+1;
Log[1]=0;
REP(i,2,n)Log[i]=Log[i/2]+1;
int v;
REP(i,1,n){
read(v);
while(v)add(v,i),++deg[i],read(v);
}
REP(i,1,n)if(!deg[i])add(rt,i),++deg[i];
}
void update(int u){
REP(i,1,18){
int f=st[u][i-1];
if(!f || !st[f][i-1])break;
st[u][i]=st[f][i-1];
}
}
int query(int x,int y){
if(dep[x]<dep[y])swap(x,y);
while(dep[x]!=dep[y]){
int d=Log[dep[x]-dep[y]];
x=st[x][d];
}
if(x==y)return x;
for(int d=18;d>=0;--d)
if(st[x][d] && st[y][d] && st[x][d]!=st[y][d])
x=st[x][d],y=st[y][d];
return st[x][0];
}
void Topsort(){
queue<int>qu;
qu.push(rt);
while(!qu.empty()){
int u=qu.front(); qu.pop();
if(u!=rt){
int t=from[u][0];
REP(i,1,from[u].size()-1)
t=query(t,from[u][i]);
st[u][0]=t; update(u);
dep[u]=dep[st[u][0]]+1;
}
for(int i=beg[u];i;i=las[i]){
int v=to[i];
--deg[v]; from[v].push_back(u);
if(!deg[v])qu.push(v);
}
}
}
void dfs(int u){
++sz[u];
REP(i,0,T[u].size()-1){
dfs(T[u][i]);
sz[u]+=sz[T[u][i]];
}
}
int main(){
File();
init();
Topsort();
REP(i,1,n)T[st[i][0]].push_back(i);
dfs(rt);
REP(i,1,n)printf("%d\n",sz[i]-1);
return 0;
}