bzoj1093: [ZJOI2007]最大半连通子图

Description

Input

第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

Output

应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3

HINT

 

对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。

 
题解:
先进行缩点,得到一张DAG,然后最大半连通子图就是这个DAG包含点数最多的链,dp一下即可
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 100005
 7 #define maxm 1000005
 8 using namespace std;
 9 char ch;
10 bool ok;
11 void read(int &x){
12     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
13     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
14     if (ok) x=-x;
15 }
16 int n,m,mod,a,b;
17 int idx,dfn[maxn],low[maxn],top,stack[maxn],cnt,belong[maxn],sum[maxn];
18 bool in[maxn];
19 int num;
20 struct Edge{
21     int u,v;
22     inline bool operator==(Edge b){return u==b.u&&v==b.v;}
23 }edge[maxm];
24 inline bool cmp(Edge a,Edge b){
25     if (a.u==b.u) return a.v<b.v;
26     return a.u<b.u;
27 }
28 int head,tail,list[maxn],f[maxn],g[maxn],deg[maxn];
29 struct Graph{
30     int tot,now[maxn],pre[maxm],son[maxm];
31     void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
32     void dfs(int u){
33         dfn[u]=low[u]=++idx,stack[++top]=u,in[u]=1;
34         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
35             if (!dfn[v]) dfs(v),low[u]=min(low[u],low[v]);
36             else if (in[v]) low[u]=min(low[u],dfn[v]);
37         if (dfn[u]==low[u]){
38             int v; ++cnt;
39             do{v=stack[top--],in[v]=0,belong[v]=cnt,sum[cnt]++;}while(v!=u);
40         }
41     }
42     void get(){
43         for (int u=1;u<=n;u++)
44             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
45                 if (belong[u]!=belong[v]) edge[++num]=(Edge){belong[u],belong[v]};
46         sort(edge+1,edge+num+1,cmp),num=unique(edge+1,edge+num+1)-edge-1;
47     }
48     void calc(){
49         head=0,tail=0;
50         for (int i=1;i<=cnt;i++) if (!deg[i]) list[++tail]=i,g[i]=1;
51         while (head<tail){
52             int u=list[++head];
53             f[u]+=sum[u];
54             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]){
55                 if (f[v]<f[u]) f[v]=f[u],g[v]=g[u];
56                 else if (f[v]==f[u]) g[v]+=g[u],g[v]%=mod;
57                 deg[v]--;
58                 if (!deg[v]) list[++tail]=v;
59             }
60         }
61         int ans1=0,ans2=0;
62         for (int i=1;i<=cnt;i++) ans1=max(ans1,f[i]);
63         printf("%d\n",ans1);
64         for (int i=1;i<=cnt;i++) if (ans1==f[i]) ans2+=g[i],ans2%=mod;
65         printf("%d\n",ans2);
66     }
67 }G1,G2;
68 int main(){
69     read(n),read(m),read(mod);
70     for (int i=1;i<=m;i++) read(a),read(b),G1.put(a,b);
71     for (int i=1;i<=n;i++) if (!dfn[i]) G1.dfs(i);
72     G1.get();
73     for (int i=1;i<=num;i++) G2.put(edge[i].u,edge[i].v),deg[edge[i].v]++;
74     G2.calc();
75     return 0;
76 }

 

posted @ 2016-01-05 08:16  chenyushuo  阅读(329)  评论(0编辑  收藏  举报