这一题的思路还是比较清晰的。虽然可以当作支配树模板,但是事实上可以上一个LCA来代替支配树。
具体来说,就是把有多个食物的消费者连到它所有食物的LCA。然后计算一遍子树大小就好了。
注意连点之前要先拓扑排序。
#include<iostream>
#include<cstdio>
#include<queue>
#define Swap(A,B) (A^=B^=A^=B)
struct ee{
int v;
int nxt;
}e[2500005];
//h,树上的节点。g,拓扑排序的节点。to,每个节点的所有父亲。
int h[70000],g[70000],et=0,dep[70000],fa[70000][18],in[70000],to[70000],sz[70000],loc[70000];
int n,tp=0;
inline void add(int *H,int U,int V){
if(U==V){
return;
}
e[++et]=(ee){V,H[U]};
H[U]=et;
}
inline void srt(){
std::queue<int> q;
for(int i=1;i<=n;++i){
if(!in[i]){
q.push(i);
}
}
int p=0;
while(!q.empty()){
p=q.front();
q.pop();
loc[++tp]=p;
for(int i=g[p];i;i=e[i].nxt){
--in[e[i].v];
if(!in[e[i].v]){
q.push(e[i].v);
}
}
}
}
inline int lca(int X,int Y){
if(dep[X]<dep[Y]){
Swap(X,Y);
}
for(int i=17;i>=0;--i){
if(dep[X]-(1<<i)>=dep[Y]){
X=fa[X][i];
}
}
if(X==Y){
return X;
}
for(int i=17;i>=0;--i){
if(fa[X][i]!=fa[Y][i]){
X=fa[X][i],Y=fa[Y][i];
}
}
return fa[X][0];
}
inline void prpr(){
int nw=0;
for(int i=1,j;i<=n;++i){
j=loc[i];
nw=e[to[j]].v;
for(int k=to[j];k;k=e[k].nxt){
nw=lca(nw,e[k].v);
}
// 请注意这里的nw可能不存在任何父亲节点。
add(h,nw,j);
fa[j][0]=nw;
dep[j]=dep[nw]+1;
for(int k=1;k<=17;++k){
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
inline void dfs(int X){
for(int i=h[X];i;i=e[i].nxt){
dfs(e[i].v);
sz[X]+=sz[e[i].v];
}
++sz[X];
}
void init(){
scanf("%d",&n);
int x;
for(int i=1;i<=n;++i){
scanf("%d",&x);
while(x){
++in[i];
add(g,x,i);
add(to,i,x);
scanf("%d",&x);
}
}
srt();
prpr();
dfs(0);
for(int i=1;i<=n;++i){
printf("%d\n",sz[i]-1);
}
}
int main(){
init();
return 0;
}