1. 程式人生 > >UVALive 5135 Mining Your Own Bussiness【tarjan點雙】

UVALive 5135 Mining Your Own Bussiness【tarjan點雙】

LINK1

LINK2


題目大意

給你一個無向連通圖,讓你給一些點染上黑色,需要滿足染色之後,斷開任意一個節點,要滿足任意一個聯通塊中剩下的節點中至少有一個黑點

思路

一開始想的是把每一個點雙聯通分量都把除了割點的size乘上

然後發現隨手卡掉

然後發現一下性質

首先所有相鄰點雙聯通分量一定有公共的割點

如果一個雙聯通分量裡面只包含了一個割點,那麼如果斷掉這個割點那麼這個雙聯通分量就被孤立了

所以這樣的雙聯通分量至少選擇一個點

然後如果一個雙聯通分量有大於等於兩個割點,就算一個被割掉了另外一邊至少連線著1個只有一個割點的點雙聯通分量

那麼就很容易做了

特判一下如果整張圖都是一個雙聯通分量那麼就是任意選兩個點就可以了


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x;
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
typedef pair<int, int> pi;
#define fi first
#define se second
const int N = 5e4 + 10;
struct Edge {
  int v, nxt;
} E[N << 1];
stack<pi > st;
int head[N], tot = 0, ind = 0, cnt_bcc = 0;
int n, m, dfn[N], low[N], siz[N], bel[N];
bool iscut[N];
vector<int> g[N];
void init() {
  fu(i, 1, N - 1) dfn[i] = low[i] = bel[i] = head[i] = siz[i] = 0, iscut[i] = 0;
  tot = ind = cnt_bcc = 0;
}
void add(int u, int v) {
  E[++tot] = (Edge) {v, head[u]};
  head[u] = tot;
}
void tarjan(int u, int fa) {
  dfn[u] = low[u] = ++ind;
  int num = 0;
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].v;
    if (v == fa) continue;
    if (!dfn[v]) {
      st.push(pi(u, v));
      ++num;
      tarjan(v, u);
      low[u] = min(low[u], low[v]);
      if (low[v] >= dfn[u]) {
        iscut[u] = 1;
        g[++cnt_bcc].clear();
        pi now;
        do {
          now = st.top(); st.pop();
          if (bel[now.fi] != cnt_bcc) {
            g[cnt_bcc].push_back(now.fi);
            bel[now.fi] = cnt_bcc;
          } 
          if (bel[now.se] != cnt_bcc) {
            g[cnt_bcc].push_back(now.se);
            bel[now.se] = cnt_bcc;
          }
        } while (now.fi != u || now.se != v);
      }
    } else low[u] = min(low[u], dfn[v]);
  }
  if (num < 2 && !fa) iscut[u] = 0;
}
void solve() {
  n = 0;
  init();
  fu(i, 1, m) {
    int u, v;
    Read(u), Read(v);
    add(u, v);
    add(v, u);
    n = max(n, max(u, v));
  }
  tarjan(1, 0);
  if (cnt_bcc == 1) {
    Write(2), putchar(' ');
    Write(ll(n) * ll(n - 1) / 2), putchar('\n');
  } else {
    ll ans1 = 0, ans2 = 1;
    fu(i, 1, cnt_bcc) {
      int cntnow = 0;
      fv(j, g[i])
        if (iscut[g[i][j]]) ++cntnow;
      if (cntnow == 1) 
        ++ans1, ans2 *= (ll) g[i].size() - 1;
    }
    Write(ans1), putchar(' ');
    Write(ans2), putchar('\n');
  }
}
int main() {
#ifdef dream_maker
  freopen("input.txt", "r", stdin);
#endif
  int id = 0;
  while (1) {
    Read(m);
    if (!m) return 0;
    printf("Case %d: ", ++id);
    solve();
  }
  return 0;
}