bzoj 1093: [ZJOI2007]最大半連通子圖【tarjan+拓撲排序+dp】
阿新 • • 發佈:2018-07-31
namespace tdi sin () top 排序 getchar read for
先tarjan縮成DAG,然後答案就變成了最長鏈,dp的同時計數即可
就是題面太唬人了,沒反應過來
#include<iostream> #include<cstdio> #include<vector> #include<cstring> #include<queue> using namespace std; const int N=100005; int n,m,mod,h[N],cnt,dfn[N],low[N],tot,bl[N],col,s[N],top,si[N],d[N],f[N],g[N],vis[N],ans1,ans2; bool v[N]; vector<pair<int,int> >a; queue<int>q; struct qwe { int no,ne,to; }e[N*10]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].no=u; e[cnt].to=v; h[u]=cnt; } void tarjan(int u) { dfn[u]=low[u]=++tot; v[s[++top]=u]=1; for(int i=h[u];i;i=e[i].ne) { if(!dfn[e[i].to]) { tarjan(e[i].to); low[u]=min(low[u],low[e[i].to]); } else if(v[e[i].to]) low[u]=min(low[u],dfn[e[i].to]); } if(dfn[u]==low[u]) { col++; while(s[top]!=u) { bl[s[top]]=col; si[col]++; v[s[top--]]=0; } bl[s[top]]=col; si[col]++; v[s[top--]]=0; } } int main() { n=read(),m=read(),mod=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); for(int i=1;i<=cnt;i++) if(bl[e[i].no]!=bl[e[i].to]) a.push_back(make_pair(bl[e[i].no],bl[e[i].to])); memset(h,0,sizeof(h)); cnt=0; for(int i=0;i<a.size();i++) add(a[i].first,a[i].second),d[a[i].second]++; for(int i=1;i<=col;i++) { if(!d[i]) q.push(i); f[i]=si[i],g[i]=1; } while(!q.empty()) { int u=q.front(); q.pop(); for(int i=h[u];i;i=e[i].ne) { d[e[i].to]--; if(!d[e[i].to]) q.push(e[i].to); if(vis[e[i].to]==u) continue; if(f[e[i].to]<f[u]+si[e[i].to]) { f[e[i].to]=f[u]+si[e[i].to]; g[e[i].to]=g[u]; } else if(f[e[i].to]==f[u]+si[e[i].to]) g[e[i].to]=(g[e[i].to]+g[u])%mod; vis[e[i].to]=u; } } for(int i=1;i<=col;i++) { if(f[i]>ans1) ans1=f[i],ans2=g[i]; else if(f[i]==ans1) ans2=(ans2+g[i])%mod; } printf("%d\n%d\n",ans1,ans2); return 0; }
bzoj 1093: [ZJOI2007]最大半連通子圖【tarjan+拓撲排序+dp】