苏塞克王国是世界上创新技术的领先国家,在王国中有n个城市,标记为1到n。
由于小K的研究,我们最终能过在两个城市之间建立传输管道,一个传输管道能单向连接两个城市,即,一个从城市x到城市y的传输管道不能被用于从城市y传输到城市x。在每个城市之间的运输系统已经建立完善,因此,如果从城市x到城市y的管道和从城市y到城市z的管道都被已经被建立,人们能够立即从x到z。
小K也研究了国家政治,他认为在这m对城市(ai, bi) (1 ≤ i ≤ m)之间的传输尤其重要。他正在计划为每个重要城市对(ai, bi)建立传输管道,通过使用一个或多个传输管道,我们可以从城市ai到城市bi(但不需要从城市bi到城市ai)。我们要找出必须建立的传输管道的最小数。至今,还没有传输管道被建立,在每个城市之间也没有其他有效的传输方式。
对于第一个样例,其中一条最优路径如下图:

Input
第一行是两个以空格隔开的整数n和m(2 ≤ n ≤10^5 , 1 ≤ m ≤ 10^5 ),分别表示在苏塞克王国中的城市数和重要城市对的数。 之后m行描述重要城市对,第i行 (1 ≤ i ≤ m)包含两个以空格隔开的整数ai和bi(1 ≤ ai, bi ≤ n, ai ≠ bi),表示必须能通过一条或两条传输管道从城市ai到城市bi(但不需要从城市bi到城市ai),我们保证所有的城市对(ai, bi)是唯一的。
Output
输出满足小K目的所需要的传输管道的最小数。
Input示例
4 5 1 2 1 3 1 4 2 3 2 4
Output示例
3
将原图缩点,如果n个点是弱联通不是强连通,那么将是n-1条边。如果是强连通,那么就是形成环,n条边。
然后将不同的块连接起来,并查集。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
#define INF 0x3fffffff
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
int n, m, edge_num, Dindex, Stop, Bcnt;
int head[maxn], LOW[maxn], DFN[maxn], instack[maxn], Stack[maxn], Belong[maxn], num[maxn], mar[maxn], fa[maxn];
struct edge {
int to;
int next;
}Edge[maxn];
void init()
{
edge_num = 0;
Stop = Bcnt = Dindex = 0;
memset(Edge, -1, sizeof(Edge));
memset(head, -1, sizeof(head));
memset(LOW, 0, sizeof(LOW));
memset(DFN, 0, sizeof(DFN));
memset(instack, 0, sizeof(instack));
memset(Stack, 0, sizeof(Stack));
memset(Belong, 0, sizeof(Belong));
}
void addedge(int u, int v)
{
Edge[edge_num].to = v;
Edge[edge_num].next = head[u];
head[u] = edge_num;
edge_num++;
}
void tarjan(int i)
{
int j;
DFN[i] = LOW[i] = ++Dindex;
instack[i] = true;
Stack[++Stop] = i;
for (j = head[i]; j != -1; j = Edge[j].next)
{
int v = Edge[j].to;
if (DFN[v] == 0)
{
tarjan(v);
LOW[i] = min(LOW[i], LOW[v]);
}
else if (instack[v] == 1)
{
LOW[i] = min(LOW[i], DFN[v]);
}
}
if (DFN[i] == LOW[i])
{
Bcnt++;
do
{
j = Stack[Stop--];
instack[j] = false;
Belong[j] = Bcnt;
num[Bcnt]++;
if (num[Bcnt] != 1)
{
mar[Bcnt] = 1;
}
else
{
mar[Bcnt] = 0;
}
} while (j != i);
}
}
void input()
{
int i, u, v;
scanf("%d%d", &n, &m);
for (i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
addedge(u, v);
}
}
int find(int x)
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void cal()
{
int i, j;
for (i = 1; i <= Bcnt; i++)
{
fa[i] = i;
}
for (i = 1; i <= n; i++)
{
for (j = head[i]; j != -1; j = Edge[j].next)
{
int s = Belong[i];
int e = Belong[Edge[j].to];
int fs = find(s);
int fe = find(e);
if (fs != fe)
{
fa[fs] = fe;
num[fe] += num[fs];
mar[fe] += mar[fs];
}
}
}
}
void solve()
{
int i;
for (i = 1; i <= n; i++)
{
if (!DFN[i])
tarjan(i);
}
cal();
ll res = 0;
for (i = 1; i <= Bcnt; i++)
{
if (fa[i] == i)
{
if (mar[i] == 0)
{
res += (num[i] - 1);
}
else
{
res += num[i];
}
}
}
printf("%I64d", res);
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
init();
input();
solve();
return 0;
}