1. 程式人生 > >[BZOJ1093][ZJOI2007]最大半連通子圖

[BZOJ1093][ZJOI2007]最大半連通子圖

存在 有關 online edge semi elong clas 一行 mem

1093: [ZJOI2007]最大半連通子圖

Time Limit: 30 Sec Memory Limit: 162 MB Submit: 3710 Solved: 1464 [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

Sample Output

3
3
縮點後求DAG上最長鏈(點權)以及最長鏈的方案數 註意判重邊
#include <cstdio>
#include 
<algorithm> using namespace std; const int maxn = 100000 + 10, maxm = 1000000 + 10; int n, m, mod; struct Edge{ int to, next; Edge(){} Edge(int _t, int _n): to(_t), next(_n){} }e[maxm * 2]; int fir[maxn * 2] = {0}, cnt = 0; inline void add(int u, int v){ e[++cnt] = Edge(v, fir[u]); fir[u] = cnt; }
int belong[maxn], siz[maxn * 2] = {0}, bcnt = 0; int dfn[maxn], low[maxn], index = 0; int sta[maxn], top = 0; bool ins[maxn] = {false}; void tarjan(int u){ ins[u] = true; sta[++top] = u; dfn[u] = low[u] = ++index; for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(!dfn[v]){ tarjan(v); low[u] = min(low[u], low[v]); } else if(ins[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]){ int now; bcnt++; do{ now = sta[top--]; ins[now] = false; belong[now] = bcnt; siz[bcnt]++; }while(now != u); } } int ind[maxn * 2] = {0}, q[maxn], h, t; void tsort(){ for(int v, u = 1; u <= n; u++) for(int i = fir[u]; i; i = e[i].next){ v = e[i].to; if(belong[v] != belong[u]){ ind[belong[v]]++; add(belong[u], belong[v]); } } h = t = 0; for(int i = n + 1; i <= bcnt; i++) if(!ind[i]) q[t++] = i; int u, v; while(h != t){ u = q[h++]; for(int i = fir[u]; i; i = e[i].next){ v = e[i].to; ind[v]--; if(!ind[v]) q[t++] = v; } } } int f[maxn * 2], g[maxn * 2]; int mark[maxn * 2] = {0}; void dp(){ int u, v; for(int i = h; ~i; i--){ u = q[i]; f[u] = siz[u]; g[u] = 1; for(int j = fir[u]; j; j = e[j].next){ v = e[j].to; if(mark[v] == u) continue; mark[v] = u; if(f[v] + siz[u] > f[u]){ f[u] = f[v] + siz[u]; g[u] = g[v]; } else if(f[v] + siz[u] == f[u]) g[u] = (g[u] + g[v]) % mod; } } } int main(){ scanf("%d %d %d", &n, &m, &mod); for(int u, v, i = 1; i <= m; i++){ scanf("%d %d", &u, &v); add(u, v); } bcnt = n; for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); tsort(); dp(); int ans = 0, sum = 0; for(int i = n + 1; i <= bcnt; i++){ if(f[i] > ans){ ans = f[i]; sum = g[i]; } else if(f[i] == ans) sum = (sum + g[i]) % mod; } printf("%d\n%d\n", ans, sum); return 0; }

[BZOJ1093][ZJOI2007]最大半連通子圖