卧薪尝胆,厚积薄发。
ZJOI2007 最大半连通子图
Date: Wed Aug 01 15:52:35 CST 2018 In Category: NoCategory

Description:

求一个图的最大半联通子图大小及个数,半联通图指图中每个点对至少能从一个点到另一个点。
$1\le n \le 10^5$ $1\le m \le 10^6$

Solution:

强连通分量一定是半联通的,于是先缩点,再在 $DAG$ 上 $dp$ ,开两个数组转移即可,注意重边只计算一次,偷懒用 $map$ 判断。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
int n,m,mod;
inline int read()
{
register int res = 0;
register char c = getchar();
while(c < '0' || c > '9')c = getchar();
while('0' <= c && c <= '9')
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
#define MAXN 100010
#define MAXM 1000010
struct edge
{
int to,nxt;
}e[MAXM << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
int dfn[MAXN],low[MAXN],tot = 0;
stack<int> s;
bool v[MAXN];
int scc = 0;
int ins[MAXN],siz[MAXN];
void tarjan(int k)
{
dfn[k] = low[k] = ++tot;
s.push(k);v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(dfn[e[i].to] == 0)
{
tarjan(e[i].to);
low[k] = min(low[k],low[e[i].to]);
}
else if(v[e[i].to])low[k] = min(low[k],dfn[e[i].to]);
}
if(low[k] == dfn[k])
{
++scc;
siz[scc] = 0;
int t;
do
{
t = s.top();s.pop();
v[t] = false;
ins[t] = scc;
++siz[scc];
}while(t != k);
}
return;
}
vector<int> d[MAXN];
int f[MAXN],g[MAXN];
int ind[MAXN] = {0};
map<pair<int,int>,bool> p;
int main()
{
n = read();m = read();mod = read();
int a,b;
for(int i = 1;i <= m;++i)
{
a = read();b = read();
add(a,b);
}
for(int i = 1;i <= n;++i)
{
if(dfn[i] == 0)tarjan(i);
}
for(int k = 1;k <= n;++k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(ins[k] != ins[e[i].to])
{
d[ins[k]].push_back(ins[e[i].to]);
++ind[ins[e[i].to]];
}
}
}
queue<int> q;
for(int i = 1;i <= scc;++i)
{
if(ind[i] == 0)
{
q.push(i);
f[i] = siz[i];
g[i] = 1;
}
}
int ans1 = 0,ans2;
while(!q.empty())
{
int k = q.front();q.pop();
ans1 = max(ans1,f[k]);
for(vector<int>::iterator it = d[k].begin();it != d[k].end();++it)
{
if(f[k] + siz[*it] > f[*it])
{
f[*it] = f[k] + siz[*it];
g[*it] = g[k];
p[make_pair(k,*it)] = true;
}
else if(f[k] + siz[*it] == f[*it] && p.find(make_pair(k,*it)) == p.end())
{
g[*it] = (g[*it] + g[k]) % mod;
p[make_pair(k,*it)] = true;
}
--ind[*it];
if(ind[*it] == 0)q.push(*it);
}
}
ans2 = 0;
for(int i = 1;i <= scc;++i)
{
if(f[i] == ans1)ans2 = (ans2 + g[i]) % mod;
}
cout << ans1 << endl << ans2 << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡