[POI2006]PRO-Professor Szu

https://www.zybuluo.com/ysner/note/1251523

题面

\(n\)个别墅以及一个主建筑楼,有\(m\)条无向边,从每个别墅都有很多种不同方式走到主建筑楼。
其中不同的定义是:每条边可以走多次,如果走边的顺序有一条不同即称两方式不同。
询问经过边数最多的不同方式是多少,以及有多少个别墅有这么多方式,按照顺序输出别墅编号。

  • \(n,m\leq10^6\)

解析

显然如果一栋别墅在环内(包括自环),第一个答案就是无限。
所以在统计完答案无限的别墅后,必须缩点,才能统计其他别墅的答案。
此时判断答案无限的标准:

  • 有无自环
  • 联通块大小大于\(1\)

接下来设\(f[i]\)为走到\(i\)点的方式数。
则边界为\(f[n+1]=1\)
那么转移方程式为\(f[u]=\sum_{v\in neighbor} f[v]\)
显然为了消除后效性需要拓扑排序。
于是从主建筑楼开始拓扑排序即可。

值得注意的是:

  • 不能把主建筑楼统计进答案
  • 把答案无限的别墅和建筑的\(f[i]=inf\),必须等到该点没有入度时再进行。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e6+100,M=36501;
struct Edge{int to,nxt;}e[N<<1],e1[N<<1];
int n,m,h[N],cnt,dfn[N],low[N],sta[N],top,tim,scc,bl[N],in[N],f[N],sz[N],ans;
bool gg[N],vis[N],gu[N];
queue<int>Q;
il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
   if(ch=='-') t=-1,ch=getchar();
   while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
   return x*t;
}
il void tarjan(re int u)
{
  dfn[u]=low[u]=++tim;vis[u]=1;sta[++top]=u;
  re int v;
  for(re int i=h[u];i+1;i=e[i].nxt)
    {
      v=e[i].to;
      if(u==v) gg[v]=1;
      if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
      else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
  if(low[u]==dfn[u])
    {
      ++scc;
      do{v=sta[top];bl[v]=scc;sz[scc]++;vis[v]=0;top--;}while(u^v);
    }
}
il void Topo()
{
  f[bl[n]]=1;if(gu[bl[n]]||sz[bl[n]]>1) f[bl[n]]=M;
  fp(i,1,n) if(!in[i]) Q.push(i);
  while(!Q.empty())
    {
      re int u=Q.front();Q.pop();
      for(re int i=h[u];i+1;i=e[i].nxt)
    {
      re int v=e[i].to;--in[v];
      f[v]=min(f[v]+f[u],M);
      if(!in[v])
        {
          if((gu[v]||sz[v]>1)&&f[v]) f[v]=M;
          Q.push(v);
        }
    }
    }
}
int main()
{
  memset(h,-1,sizeof(h));
  n=gi()+1;m=gi();
  fp(i,1,m)
    {
      re int u=gi(),v=gi();
      add(v,u);
    }
  fp(i,1,n) if(!dfn[i]) tarjan(i);top=0;
  fp(u,1,n)
    for(re int i=h[u];i+1;i=e[i].nxt)
      {
    re int v=e[i].to;
    if(bl[u]^bl[v]) e1[++top]=(Edge){bl[u],bl[v]};
      }
  memset(h,-1,sizeof(h));cnt=0;
  fp(i,1,top) add(e1[i].to,e1[i].nxt),++in[e1[i].nxt];
  fp(i,1,n) if(gg[i]) gu[bl[i]]=1;
  Topo();top=0;
  fp(i,1,n-1) ans=max(ans,f[bl[i]]);
  fp(i,1,n-1) if(f[bl[i]]==ans) sta[++top]=i;
  if(ans==M) puts("zawsze");else printf("%d\n",ans);
  printf("%d\n",top);
  fp(i,1,top) printf("%d ",sta[i]);puts("");
  return 0;
}
posted @ 2018-08-20 00:46  小蒟蒻ysn  阅读(229)  评论(0编辑  收藏  举报