【BZOJ3887】【Usaco2015 Jan】Grass Cownoisseur Tarjan+Spfa

我们可以看出这个东西可以缩点成DAG,因为我们在所称的点里用特技的话,要么没用,要么削弱自己对点的收割能力与边的联通权,所以我们缩完点之后在图上枚举反向的变,因为我们只可能反向一条边,而且我们知道在这条边上走的方向,那么我们一定是在边终点回去,在边起点来,因为一来一回的这两条路径一定没有交叉所以我们找着两条路径的最大值,我们跑两边SPFA就好了,(一边正向,一边反向)。

注意在无向图Tarjan时要穷举,因为一个点可能走不完。

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100005
using namespace std;
inline int read()
{
    int sum=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        sum=(sum<<1)+(sum<<3)+ch-'0';
        ch=getchar();
    }
    return sum;
}
inline int Min(int x,int y)
{
    return x<y?x:y;
}
inline int Max(int x,int y)
{
    return x>y?x:y;
}
int dfn[MAXN],low[MAXN],when,stack[MAXN],top;
struct Tr
{
    int to,next,w;
}C[MAXN],c[MAXN<<1];
int Head[MAXN],T,head[MAXN],t;
bool in[MAXN];
inline void Add(int x,int y)
{
     C[++T].to=y;
     C[T].next=Head[x];
     Head[x]=T;
}
int belong[MAXN],sum[MAXN],num;
int n,m;
void Tarjan(int x)
{
    low[x]=dfn[x]=++when;
    stack[++top]=x;
    in[x]=1;
    for(int i=Head[x];i;i=C[i].next)
    {
        int y=C[i].to;
        if(!dfn[y])
        {
            Tarjan(y);
            low[x]=Min(low[x],low[y]);
        }
        else if(in[y])
            low[x]=Min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x])
    {
        int j;
        num++;
        do
        {
            j=stack[top--];
            in[j]=0;
            belong[j]=num;
            sum[num]++;
        }while(j!=x);
    }
}
inline void add(int x,int y,int z)
{
    c[++t].to=y;
    c[t].next=head[x];
    head[x]=t;
    c[t].w=z;
}
struct E
{
    int x,y;
}e[MAXN];
int sz;
inline void buildnew()
{
    for(int x=1;x<=n;x++)
    {
        for(int i=Head[x];i;i=C[i].next)
        {
            int y=C[i].to;
            if(belong[x]==belong[y])continue;
            e[++sz].x=belong[x];
            e[sz].y=belong[y];
            add(belong[x],belong[y],1);
            add(belong[y],belong[x],0);
        }
    }
}
int S,q[MAXN],tail,dis_to[MAXN],dis_from[MAXN];
void spfa1()
{
    memset(dis_from,-1,sizeof(dis_from));
    dis_from[S]=0;
    q[1]=S;
    top=tail=1;
    in[S]=1;
    while(top<=tail)
    {
        int x=q[top++];
        in[x]=0;
        for(int i=head[x];i;i=c[i].next)
        if(c[i].w==0)
        {
           if(dis_from[x]+sum[c[i].to]>dis_from[c[i].to])
           {
               dis_from[c[i].to]=dis_from[x]+sum[c[i].to];
               if(!in[c[i].to])
                in[c[i].to]=1,q[++tail]=c[i].to;
           }
        }
    }
}
void spfa2()
{
    memset(dis_to,-1,sizeof(dis_to));
    q[1]=S;
    top=tail=1;
    dis_to[S]=sum[S];
    in[S]=1;
    while(top<=tail)
    {
        int x=q[top++];
        in[x]=0;
        for(int i=head[x];i;i=c[i].next)
        if(c[i].w)
        {
           if(dis_to[x]+sum[c[i].to]>dis_to[c[i].to])
           {
               dis_to[c[i].to]=dis_to[x]+sum[c[i].to];
               if(!in[c[i].to])
                in[c[i].to]=1,q[++tail]=c[i].to;
           }
        }
    }
}
inline void Init()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        Add(x,y);
    }
    for(int i=1;i<=n;i++)
     if(!dfn[i])
       Tarjan(i);
    buildnew();
    S=belong[1];
    spfa1();
    spfa2();
}
int ans;
inline void work()
{
    ans=sum[S];
    for(int i=1;i<=sz;i++)
    {
        int x=e[i].y,y=e[i].x;
        if(dis_to[x]==-1||dis_from[y]==-1)continue;
        ans=Max(ans,dis_to[x]+dis_from[y]);
    }
    printf("%d",ans);
}
int main()
{
    Init();
    work();
    return 0;
}

 

posted @ 2017-07-13 18:00  TS_Hugh  阅读(177)  评论(0编辑  收藏  举报