# BZOJ 2730: [HNOI2012]矿场搭建 割点 + 乘法原理

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2362 Solved: 1093

9

1 3

4 1

3 5

1 2

2 6

1 5

6 3

1 6

3 2

6

1 2

1 3

2 4

2 5

3 6

3 7

0

Case 1: 2 4

Case 2: 4 1

## HINT

Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6)；

Case 2 的一组解为(4,5,6,7)。
Source

## day1

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
const int MAXM = 10000;
int head[MAXN], tail, cnt, timer, dfn[MAXN], low[MAXN], n;
int iscut[MAXN];
long long sz;
struct Line{ int to, nxt; }line[MAXM];
void add_line( int from, int to ) {
line[tail].to = to;
}
void init( ) {
tail = 0; cnt = 0; timer = 0; n = 0;
memset( dfn, 0, sizeof( dfn ) );
memset( iscut, 0, sizeof( iscut ) );
}
void Tarjan( int u, int fa ) {
timer++; dfn[u] = low[u] = timer;
for( register int i = head[u]; i; i = line[i].nxt ) {
int v = line[i].to;
if( v == fa ) continue;
if( !dfn[v] ) {
Tarjan( v, u );
low[u] = min( low[u], low[v] );
if( low[v] >= dfn[u] ) iscut[u]++ ;
} else low[u] = min( low[u], dfn[v] );
}
}
void dfs( int u, int tim ) {
dfn[u] = 1; sz++;
for( register int i = head[u]; i; i = line[i].nxt ) {
int v = line[i].to;
if( iscut[v] && dfn[v] < tim ) { cnt++; dfn[v] = tim; continue; }
if( !dfn[v] ) dfs( v, tim );
}
}
int main( ) { int kase = 0 ,m;
while( scanf( "%d", &m ) != EOF && m != 0 ) {
init();
for( register int i = 1; i <= m; i++ ) { int u, v;
scanf( "%d%d", &u, &v );
n = max( n, max( u, v ) );
}
for( register int i = 1; i <= n; i++ )
if( !dfn[i] ) iscut[i] = -1, Tarjan( i, -1 );
for( register int i = 1; i <= n; i++ )
if( iscut[i] ) cnt++;
memset( dfn, 0, sizeof( dfn ) );
long long ans1 = 0LL, ans2 = 1LL;
if( cnt == 0 ) ans1 = 2LL, ans2 = ( n - 1 ) * 1LL * n  / 2;
else {
for( register int i = 1; i <= n; i++ ) {
cnt = 0; sz = 0;
if( !dfn[i] && !iscut[i] ) sz = 0LL, dfs( i, i );
if( cnt == 1 ) ans2 *= sz, ans1++;
}
} kase++;
printf( "Case %d: %lld %lld\n", kase, ans1, ans2 );
}
return 0;
}