版权声明:虽然我很菜,不过转载请标明出处。 https://blog.csdn.net/Patrickpwq/article/details/86622040
(我怎么又双叒叕发烧了...)
不难想到 对于一个生产者 它死了 所有它的子树就都死了
换句话说 对于一个消费者 它死 当且仅当它的所有食物都死了 什么时候所有食物都死了呢?——最顶端的生产者死了。否则,那消费者一定能至少找到一种食物
假如我们能够建出这样的一颗树就是极好的 不妨先来考虑建树的过程 对于新加入的点now 首先我们确定now是否为生产者 否则 将now放在食物们lca的儿子的地方即可
那肯定不能直接1~n枚举 这样找出来的LCA是错的 由于没有环 考虑拓扑先确定层次
#include<bits/stdc++.h>
const int N=65535;
using namespace std;
int n;
int first[N],tot;
struct Edge
{
int to,next;
}edge[2*N];
inline void addedge(int x,int y)
{
tot++;
edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot;
}
int in[N],topo[N],num;
void Topo_sort()
{
queue <int> q;
for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
while(!q.empty())
{
int now=q.front();
q.pop();
topo[++num]=now;
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
in[vis]--;
if(!in[vis]) q.push(vis);
}
}
}
vector <int> e[N];
int father[N],depth[N],up[N][20];
inline int getlca(int x,int y)
{
if(depth[x]<depth[y]) swap(x,y);
for(int i=19;i>=0;i--) if(depth[up[x][i]]>=depth[y]) x=up[x][i];
if(x==y) return x;
for(int i=19;i>=0;i--) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];
return up[x][0];
}
inline void update(int now)
{
for(int i=1;i<=19;i++) up[now][i]=up[up[now][i-1]][i-1];
}
void build()
{
depth[n+1]=1;
for(int i=num;i>=1;i--)
{
int now=topo[i];
if(first[now]==0) //生产者
{
e[now].push_back(n+1); e[n+1].push_back(now);
up[now][0]=n+1;
depth[now]=2;
continue;
}
int lca=edge[first[now]].to;
for(int u=edge[first[now]].next;u;u=edge[u].next)
{
int vis=edge[u].to;
lca=getlca(lca,vis);
}
up[now][0]=lca;
e[now].push_back(lca); e[lca].push_back(now);
depth[now]=depth[lca]+1;
update(now);
}
}
int sum[N];
void dfs(int now,int fa)
{
sum[now]=1;
for(int i=0;i<e[now].size();i++)
{
int vis=e[now][i];
if(vis==fa) continue;
dfs(vis,now);
sum[now]+=sum[vis];
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n;
for(int i=1,x;i<=n;i++)
{
cin>>x;
while(x)
{
addedge(i,x); //每个点连向它的食物 方便build
in[x]++;
cin>>x;
}
}
Topo_sort();
build();
dfs(n+1,0);
for(int i=1;i<=n;i++) cout<<sum[i]-1<<endl;
return 0;
}