bzoj [HAOI2006] 受欢迎的牛 tarjan

Description

每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

***注意要被所有的牛支持****

解:缩点之后求根那个点的大小

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#define mem(a,b) memset(a,b,sizeof a)
#define en '\n'
#define maxn 100005
using namespace std;
typedef long long ll;
template<class T>void rd(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}
const int inf =1<<29;
int head[maxn];
int n,m,tot;
int cnt=0;
int low[maxn],dfn[maxn],num,sta[maxn],top,ins[maxn],sum=0;
int cost[maxn],c[maxn],c_num[maxn];
int tot2;
int ans_sum[maxn];
int st[maxn],ed[maxn],sz[maxn];
bool vis[maxn];
int rudu[maxn],chudu[maxn],val[maxn],mx,ren;
struct node{
int v,nxt;
}edge[maxn<<3];
void add(int x,int y){
    edge[++tot]=node{y,head[x]};head[x]=tot;
}
void tarjan(int x){
    dfn[x]=low[x]=++num;
    sta[++top]=x,
        ins[x]=1;
    for(int i=head[x];i;i=edge[i].nxt){
        if(!dfn[edge[i].v]){
            tarjan(edge[i].v);
            low[x]=min(low[x],low[edge[i].v]);
        }else if(ins[edge[i].v])low[x]=min(low[x],dfn[edge[i].v]);
    }
    if(dfn[x]==low[x]){
            cnt++;
            int y;
            do{
                y=sta[top--];ins[y]=0;
                c[y]=cnt;
                c_num[cnt]+=1;
            }while(x!=y);
        }
}
vector<int>vec[maxn];
void dfs(int x,int fa){
    val[x]=sz[x];
    for(int i=0;i<vec[x].size();i++){
        int y=vec[x][i];if(y==fa)continue;
        dfs(y,x);
        val[x]+=val[y];
    }
}
signed main()
{
    #ifdef local
    freopen("input2.txt","r",stdin);
    #endif
        cin>>n>>m;
        mem(head,0);
        tot=tot2=num=cnt=0;
        mem(dfn,0);
        mem(chudu,0);
        mem(rudu,0);
        for(int i=0;i<m;i++){
            int x,y;scanf("%d%d",&x,&y);st[i]=x;ed[i]=y;add(x,y);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i])tarjan(i);
        }
        #define pb push_back
        for(int i=1;i<=n;i++)sz[c[i]]+=1;
        for(int i=0;i<m;i++){
            if(c[st[i]]!=c[ed[i]]){
                chudu[c[st[i]]]+=1;
                vec[c[ed[i]]].pb(c[st[i]]);
            }
        }
        int ttt=0;
        for(int i=1;i<=cnt ;i++){
            if(!chudu[i]){
                ttt+=1;
                dfs(i,0);
                ren=sz[i];
            }
        }
        if(ttt>1){
            cout<<0<<en;
        }else{
        cout<<ren<<en;
        }
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值