bzoj2815: [ZJOI2012]灾难

话说这个就是灭绝树/支配树?感觉就是LCA的思路题嘛。

对于一个生物,它死只有它的所有食物死,然而我们询问的是死一个多少死

我们可以建出一棵树,父亲连向子节点当且仅当父亲死了孩子必死,而且是距离最近的

这是一个有向无环图,我们可以让生产者向消费者连边,进行拓扑排序

当拓扑到当前点的时候,它的食物就已经在树里面了,而当前点死最近的方法就是它所以食物的LCA死

那么就这样建边

答案就是子树大小-1

囧LCA写错WA一发

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
struct node{int x,y,next;};

node e[110000];int elen,elast[110000];
void eins(int x,int y)
{
    elen++;
    e[elen].x=x;e[elen].y=y;
    e[elen].next=elast[x];elast[x]=elen;
}
int Bin[30],f[30][110000],dep[110000]; int cc;
void add(int x,int F)
{
    eins(F,x);dep[x]=dep[F]+1;
    f[0][x]=F;cc++;
    for(int i=1;Bin[i]<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]];
}
int LCA(int x,int y)
{
    if(x==-1)return y;
    
    if(dep[x]<dep[y])swap(x,y);
    for(int i=25;i>=0;i--)
        if(dep[x]-dep[y]>=Bin[i])x=f[i][x];
    if(x==y)return x;
    
    for(int i=25;i>=0;i--)
        if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
    return f[0][x];
}

//---------------------------------------------------------------------------------------------------------------------------------

node a[2100000];int len,last[110000],du[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
vector<int>vec[110000];
int getfa(int x)
{
    if(x==23)
    {
        int t;t++;
    }
    int ret=-1;
    for(int i=0;i<vec[x].size();i++)
        ret=LCA(ret,vec[x][i]);
    //if(ret==-1)ret=0;
    return ret;
}
int top,sta[110000];
void topsort(int n)
{
    for(int i=1;i<=n;i++)
        if(du[i]==0)sta[++top]=i,add(i,0);
    while(top!=0)
    {
        int x=sta[top];top--;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            du[y]--;
            if(du[y]==0)
                sta[++top]=y,add(y,getfa(y));
        }
    }
}

//---------------------------------------------------------------------------------------------------------------------------------

int tot[110000];
void dfs(int x)
{
    tot[x]=1;
    for(int k=elast[x];k;k=e[k].next)
    {
        int y=e[k].y;
        dfs(y);
        tot[x]+=tot[y];
    }
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,x;
    scanf("%d",&n); len=0;
    for(int i=1;i<=n;i++)
    {
        while(scanf("%d",&x)!=EOF)
        {
            if(x==0)break;
            ins(x,i);du[i]++;
            vec[i].push_back(x);
        }
    }
    elen=0;
    Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
    memset(f[0],-1,sizeof(f[0]));cc=0;
    topsort(n);
    dfs(0);
    for(int i=1;i<=n;i++)
        printf("%d\n",tot[i]-1);
    
    return 0;
}

 

转载于:https://www.cnblogs.com/AKCqhzdy/p/10177278.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值