• [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;
    } 

     

  • 相关阅读:
    图像
    链接
    列表
    常见的文本标签
    注释有哪些作用?你会用使用注释来做什么?
    如何使用浏览器查看源代码?查看源码的快捷方式是什么?
    编辑HTML源代码
    <html>,<head>,<body>,<title>的作用
    HTML中的标签和属性
    记录Git的安装过程
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8566979.html
Copyright © 2020-2023  润新知