bzoj2815 灾难
https://www.cnblogs.com/Slrslr/p/9578471.html
构造一颗“灭绝树”。即对于灭绝树上的两个点x,y,如果x为y的祖先,则x的灭亡会直接导致y的灭亡也就是说X是Y的食物。下面进行构造:首先进行拓扑排序,然后按照排序的逆序构造,保证对于图中的任意x->{y},都能使x构造前,{y}已经完成构造。然后找到{y}在灭绝树上面的位置,显然{y}在灭绝树上的公共祖先的灭绝会导致{y}全部灭绝进而导致x灭绝。于是可以求它们的lca,那么lca就是x在灭绝树上面的祖先。最后跑一边dfs统计子树大小即可。实际上,这是求有向图必经点的一个特殊问题(无环),实际上可以直接用支配树解决.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define M 100010
using namespace std;
int n,num1,num2,num3;
int head1[M],head2[M],head3[M],in[M],topo[M],deep[M],ans[M],fa[M][20];
struct point{int to,next;}e1[M<<1],e2[M<<1],e3[M<<1];
void add1(int from,int to)
//from是食主人,TO是被吃的
{
e1[++num1].next=head1[from];
e1[num1].to=to;
head1[from]=num1;
}
void add2(int from,int to)
{
e2[++num2].next=head2[from];
e2[num2].to=to;
head2[from]=num2;
}
void add3(int from,int to)
//from是食主人,TO是被吃的
{
e3[++num3].next=head3[from];
e3[num3].to=to;
head3[from]=num3;
}
void topsort()
{
queue<int>q;
for(int i=1;i<=n;i++)
if(!in[i]) //将没有前置食物的动物加入
q.push(i);
int tot=0;
while(!q.empty())
{
int now=q.front();
q.pop();
topo[++tot]=now;
for(int i=head2[now];i;i=e2[i].next)
{
int to=e2[i].to;
in[to]--;
if(!in[to]) q.push(to);
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
for(int i=18;i>=0;i--)
if(deep[fa[x][i]]>=deep[y])
x=fa[x][i];
if(x==y)return y;
for(int i=18;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void dfs(int x)
{
for(int i=head3[x];i;i=e3[i].next)
{
int to=e3[i].to;
dfs(to);
ans[x]+=ans[to];
}
ans[x]++;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
while(1)
{
int x;
scanf("%d",&x);
//x是第I种动物的食物
if(!x) break;
add1(i,x);
add2(x,i);
in[i]++;//I这种动物的食物有几种
}
}
topsort();
for(int i=1;i<=n;i++)
{
int x=e1[head1[topo[i]]].to;
for(int j=head1[topo[i]];j;j=e1[j].next)
x=lca(x,e1[j].to);//取出所有食物的等级最高的
add3(x,topo[i]);//建立一条边从X到它的食材等级最高的那个
deep[topo[i]]=deep[x]+1;//注意DEEP值最大,说明越是自然界食物链的上层
fa[topo[i]][0]=x;
for(int j=1;j<=18;j++) //由于在不断建树,所以不断建立LCA的准备工作
fa[topo[i]][j]=fa[fa[topo[i]][j-1]][j-1];
}
dfs(0);//统计每个点的子树大小
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]-1);
return 0;
}

浙公网安备 33010602011771号