【51nod】小k的技术(tarjan+带权并查集)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coldfresh/article/details/82388763

这里写图片描述
这里写图片描述

思路:用tarjan缩点以后,在带权并查集,需判断一个并查集里,是否含有强连通分量,如果有贡献就是点集大小,如果没有减1.
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 200005
#define maxx 100005
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int head[maxn],to[maxx],_next[maxx];
int edge;
void addEdge(int x,int y)
{
    to[++edge]=y,_next[edge]=head[x],head[x]=edge;
}
inline int _min(int a,int b)
{
    return a>b?b:a;
}
int DFN[maxn],low[maxn],ind;
bool inS[maxn];
int st[maxn],cnt;
int be[maxn],tot;
int w[maxn];
bool sign[maxn];
void tarjan(int u)
{
    DFN[u]=low[u]=++ind;
    st[++cnt]=u;
    inS[u]=true;
    for(int i=head[u];i;i=_next[i])
    {
        int v=to[i];
        if(!DFN[v])
        {
            tarjan(v);
            low[u]=_min(low[u],low[v]);
        }
        else if(inS[v])low[u]=_min(low[u],DFN[v]);
    }
    if(DFN[u]==low[u])
    {
        ++tot;int now;
        do
        {
            ++w[tot];
            now=st[cnt--];
            be[now]=tot;
            inS[now]=false;
        }while(now!=u);
        if(w[tot]>1)sign[tot]=true;
    }
}
int pre[maxn];
int _find(int x)
{
    return pre[x]==x?x:pre[x]=_find(pre[x]);
}
int main()
{
    cin>>n>>m;
    int x,y;
    for(int i=0;i<m;++i)
    {
        scanf("%d%d",&x,&y);
        addEdge(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!DFN[i])tarjan(i);

    for(int i=1;i<=tot;i++)pre[i]=i;
    for(int u=1;u<=n;u++)
        for(int i=head[u];i;i=_next[i])
        {
            int v=to[i];
            if(be[u]!=be[v])
            {
                int uu=_find(be[u]);
                int vv=_find(be[v]);
                if(uu!=vv)
                {
                    pre[vv]=uu;
                    w[uu]+=w[vv];
                    sign[uu]|=sign[vv];
                }
            }
        }
    int ans=0;
    for(int i=1;i<=tot;++i)
        if(pre[i]==i)
        {
            if(sign[i])ans+=w[i];
            else ans+=w[i]-1;
        }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Coldfresh/article/details/82388763
今日推荐