#Tarjan,拓撲排序#洛谷 3436 [POI2006]PRO-Professor Szu
阿新 • • 發佈:2020-11-04
分析
考慮有向圖縮點然後拓撲排序,
最噁心的地方是這題有自環,
一旦存在自環就意味著答案一定超過閾值
其實更難過的是Tarjan大小寫寫錯沒有發現qwq
程式碼
#include <cstdio> #include <cctype> #include <stack> #include <queue> #define rr register using namespace std; const int N=1000011; stack<int>stac; queue<int>q; struct node{int y,next;}e[N],E[N]; int dfn[N],low[N],v[N],col[N],siz[N],m,ans,Ans; int deg[N],n,et,Et,cnt,tot,as[N],hs[N],dp[N]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline signed min(int a,int b){return a<b?a:b;} inline void tarjan(int x){ dfn[x]=low[x]=++tot, v[x]=1,stac.push(x); for (rr int i=hs[x];i;i=E[i].next) if (!dfn[E[i].y]){ tarjan(E[i].y); low[x]=min(low[x],low[E[i].y]); }else if (v[E[i].y]) low[x]=min(low[x],dfn[E[i].y]); if (dfn[x]==low[x]){ rr int y; ++cnt; do{ y=stac.top(); stac.pop(); col[y]=cnt,++siz[cnt],v[y]=0; }while (x^y); } } signed main(){ n=iut()+1,m=iut(); for (rr int i=1;i<=m;++i){ rr int y=iut(),x=iut(); E[++Et]=(node){y,hs[x]},hs[x]=Et; } for (rr int i=1;i<=n;++i) if (!dfn[i]) tarjan(i); for (rr int i=1;i<=n;++i) for (rr int j=hs[i];j;j=E[j].next) if (i==E[j].y) ++siz[col[i]]; else if (col[i]^col[E[j].y]){ e[++et]=(node){col[E[j].y],as[col[i]]}, as[col[i]]=et,++deg[col[E[j].y]]; } for (rr int i=1;i<=cnt;++i) if (!deg[i]) q.push(i); dp[col[n]]=1,v[col[n]]=1; while (!q.empty()){ rr int x=q.front(); q.pop(); for (rr int i=as[x];i;i=e[i].next){ if (!(--deg[e[i].y])) q.push(e[i].y); if (v[x]) v[e[i].y]=1; dp[e[i].y]+=dp[x]; if (siz[e[i].y]>1&&v[e[i].y]) dp[e[i].y]=36501; if (dp[e[i].y]>36501) dp[e[i].y]=36501; } } for (rr int i=1;i<=cnt;++i) if (v[i]&&ans<dp[i]) ans=dp[i]; if (ans==36501) printf("zawsze\n"); else printf("%d\n",ans); for (rr int i=1;i<=n;++i) if (v[col[i]]&&ans==dp[col[i]]) ++Ans; printf("%d\n",Ans); for (rr int i=1;i<=n;++i) if (v[col[i]]&&ans==dp[col[i]]) printf("%d ",i); return 0; }