bzoj 2815: [ZJOI2012]灾难 支配树

来源:互联网 发布:手机版淘宝盗图技巧 编辑:程序博客网 时间:2024/05/17 21:46

题意

给出一个有向无环图,问把每个点分别删掉后有多少个点不能从入读为0的点到达。
n<=100000

分析

直接把支配树建出来,然后一个点的答案就是它在支配树上的size-1.

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int N=100005;int n,cnt,last[N],ls[N],a[N],fa[N][20],dep[N],d[N],size[N];struct edge{int to,next;}e[N*30];queue<int> que;int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].next=ls[v];ls[v]=cnt;}void topusort(){    que.push(n+1);    int a1=0;    while (!que.empty())    {        int u=que.front();que.pop();a[++a1]=u;        for (int i=last[u];i;i=e[i].next)        {            d[e[i].to]--;            if (!d[e[i].to]) que.push(e[i].to);        }    }}int get_lca(int x,int y){    if (dep[x]<dep[y]) swap(x,y);    for (int i=16;i>=0;i--)        if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];    if (x==y) return x;    for (int i=16;i>=0;i--)        if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];    return fa[x][0];}int main(){    n=read();    for (int i=1;i<=n;i++)    {        int x=read();        while (x) addedge(x,i),x=read(),d[i]++;;    }    for (int i=1;i<=n;i++) if (!d[i]) addedge(n+1,i),d[i]++;    topusort();    for (int i=1;i<=n+1;i++)    {        int x=a[i],y=0;        for (int j=ls[x];j;j=e[j].next)            if (!y) y=e[j].to;            else y=get_lca(e[j].to,y);        fa[x][0]=y;dep[x]=dep[y]+1;        for (int j=1;j<=16;j++) fa[x][j]=fa[fa[x][j-1]][j-1];    }    for (int i=n+1;i>=1;i--) size[a[i]]++,size[fa[a[i]][0]]+=size[a[i]];    for (int i=1;i<=n;i++) printf("%d\n",size[i]-1);    return 0;}
原创粉丝点击