【BZOJ1093】最大半联通子图
1093: [ZJOI2007]最大半连通子图
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 3111 Solved: 1228
[Submit][Status][Discuss]
Description
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,
则称G'是G的一个导出子图。若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。若G'是G所有半连通子图
中包含节点数最多的,则称G'是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。
Input
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
00000, M ≤1000000;对于100%的数据, X ≤10^8
Output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
Sample Input
6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
3
3
HINT
Source
Sol
涨姿势了 最长路还能这么搞……
首先tarjan缩点成DAG,然后每个点拓扑排序(其实就是求最长路,边权为scc[v]) 然后dp统计答案 没了

/*To The End Of The Galaxy*/ #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<iomanip> #include<bitset> #include<stack> #include<map> #include<set> #include<cmath> #include<complex> #define debug(x) cerr<<#x<<"="<<x<<endl #define INF 0x7f7f7f7f #define llINF 0x7fffffffffffll #define P(x,y) (((x-1)*c)+y) using namespace std; typedef pair<int,int> pii; typedef long long ll; inline int init() { int now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } inline long long llinit() { long long now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } struct edge { int from,to,val,pre; }Edge[2000005],e[2000005]; int dfn[100005],low[100005],dfs_time,cnt,n,m; bool instack[100005]; stack<int> st; map<pii,int> mp; int in[100005],mod,dis[100005],f[100005]; int scc[100005],head[100005],bel[100005],topt,sccnumber; inline void addedge(int from,int to,int val) { ++cnt; Edge[cnt]=((edge){from,to,val,head[from]}); head[from]=cnt; } inline void tarjan(int now) { dfn[now]=low[now]=++dfs_time; st.push(now);instack[now]=1; for(int j=head[now];j;j=Edge[j].pre) { if(!dfn[Edge[j].to]) { tarjan(Edge[j].to); low[now]=min(low[now],low[Edge[j].to]); } else if(instack[Edge[j].to]) { low[now]=min(low[now],dfn[Edge[j].to]); } } if(dfn[now]==low[now]) { ++sccnumber; while(1) { topt=st.top();st.pop(); bel[topt]=sccnumber; scc[sccnumber]++; instack[topt]=false; if(dfn[topt]==low[topt])break; } } } queue<int> q; int maxnode,ans; inline void rebuild() { for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } for(int i=1;i<=cnt;i++) { e[i]=Edge[i]; } memset(head,0,sizeof(head)); for(int i=1;i<=cnt;i++) { if(bel[e[i].from]!=bel[e[i].to]&&!mp[make_pair(bel[e[i].from],bel[e[i].to])]) { in[bel[e[i].to]]++; mp[make_pair(bel[e[i].from],bel[e[i].to])]=1; addedge(bel[e[i].from],bel[e[i].to],1); } } for(int i=1;i<=sccnumber;i++) { if(in[i]==0) { q.push(i); dis[i]=scc[i]; f[i]=1; } else { dis[i]=0; } } } inline void toposort() { int now; while(!q.empty()) { now=q.front();q.pop(); for(int j=head[now];j;j=Edge[j].pre) { in[Edge[j].to]--; if(in[Edge[j].to]==0)q.push(Edge[j].to); if(dis[now]+scc[Edge[j].to]>dis[Edge[j].to]) { dis[Edge[j].to]=dis[now]+scc[Edge[j].to]; f[Edge[j].to]=f[now]; } else if(dis[now]+scc[Edge[j].to]==dis[Edge[j].to]) { f[Edge[j].to]=(f[Edge[j].to]+f[now])%mod; } } } } int main() { int a,b; n=init();m=init();mod=init(); for(int i=1;i<=m;i++) { a=init();b=init(); addedge(a,b,1); } rebuild(); toposort(); for(int i=1;i<=n;i++) { if(maxnode<dis[i]) { maxnode=dis[i]; ans=f[i]; } else if(maxnode==dis[i]) { ans=(ans+f[i])%mod; } } printf("%d\n%d\n",maxnode,ans); return 0; }