[ZJOI2012]灾难

题解:

首先很容易想到拓扑排序,但是会发现一个节点会由多个决定

但是我们还不知道他们的关系

那么如果我们知道了决定它的那些节点的关系

我们就可以做了

所以就先拓扑排序,按照拓扑顺序进行

然后 我们需要找到最后面的那个能决定所有决定这个节点的那个点(有点绕)

这个可以用倍增来维护(其实就是lca)

最后统计答案就统计一下子树大小就可以了

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5; 
int cd[N],head[N],p[N],cnt,lca;
int bz[N][20],dep[N],count2[N],l,n,m;
int b[N];
bool ff[N];
struct re{
    int a,b;
}a[N*100];
void arr(int x,int y)
{
    a[++l].a=head[x];
    a[l].b=y;
    head[x]=l;
}
int get_lca(int x,int y)
{
    if (dep[x]<dep[y]) swap(x,y);
    for (int i=18;i>=0;i--)
      if (dep[bz[x][i]]>=dep[y])
        x=bz[x][i];
    if (x==y) return (x);
    for (int i=18;i>=0;i--)
      if (bz[x][i]!=bz[y][i])
        x=bz[x][i],y=bz[y][i];
    return (bz[x][0]);
}
void dfs(int x)
{
    int u=head[x];
    while (u)
    {
        int v=a[u].b;
        dfs(v);
        u=a[u].a;
        count2[x]+=count2[v];
    }
    count2[x]++;
}
queue<int> q;
int main()
{
    freopen("noip.in","r",stdin);
    freopen("noip.out","w",stdout);
    std::ios::sync_with_stdio(false);
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        while (cin>>m&&m)
        {
            cd[m]++; arr(i,m);
        }
    }
    for (int i=1;i<=n;i++)
      if (cd[i]==0) q.push(i);
    while (!q.empty())
    {
        int x=q.front(); q.pop();
        p[++cnt]=x;
        int u=head[x],v,cnt2=0;
        while (u)
        {
            v=a[u].b; cd[v]--;
            if (!cd[v]) q.push(v);
            cnt2++;
            u=a[u].a;
        }
        if (cnt2==1) bz[x][0]=v;
        if (cnt2==0) bz[x][0]=0,dep[x]=1;
    }
    for (int i=n;i;i--)
    {
       int xx=p[i];
       int u=head[xx],cnt2=0,lca=0;
       while (u)
       {
              int x=a[u].b;
              b[++cnt2]=x;
              u=a[u].a;
       }
       if (cnt2>=1)
       {
            lca=b[1];
         for (int i=2;i<=cnt2;i++)
         {
               lca=get_lca(lca,b[i]);
         }
         bz[xx][0]=lca; dep[xx]=dep[lca]+1;
       }
       for (int i=1;i<=18;i++)
         bz[xx][i]=bz[bz[xx][i-1]][i-1];
    }
    memset(head,0,sizeof(head)); l=0;
    for (int i=1;i<=n;i++)
    {
        if (bz[i][0])
          arr(bz[i][0],i);
        else q.push(i);
    }
    while (!q.empty())
    {
        int x=q.front(); q.pop();
        dfs(x);
    }
    for (int i=1;i<=n;i++) cout<<count2[i]-1<<endl;
    return 0;
} 

 

posted @ 2018-03-14 13:18  尹吴潇  阅读(208)  评论(0编辑  收藏  举报