题意
传送门 P5058 [ZJOI2004]嗅探器
题解
若两个信息中心位于不同的联通分量,则无解;反之,答案为信心中心间编号最小的割点。求点双连通分量,缩点后得到一棵树,用信息中心间的路径上的割点更新答案即可。
当
n
n
n 较小时,也可以简单地不通过缩点求解。枚举割点,判断信息中心是否处于不同的连通分量即可。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 2e5 + 5;
int N, idx[MAXN];
vector<int> G[MAXN], nG[MAXN * 2];
int dep[MAXN * 2], par[MAXN * 2];
int low[MAXN], stk[MAXN], top, rt, dcc_num;
vector<int> dcc[MAXN];
bool cut[MAXN];
set<int> vs;
void dfs(int u, int p, int d)
{
stk[top++] = u;
dep[u] = low[u] = d, vs.insert(u);
int s = 0;
for (int v : G[u])
{
if (dep[v] == -1)
{
dfs(v, u, d + 1);
low[u] = min(low[u], low[v]);
if (dep[u] <= low[v])
{
++s;
if (s > 1 || u != rt)
cut[u] = 1;
dcc[dcc_num].clear();
int w;
do
{
w = stk[--top];
dcc[dcc_num].pb(w);
} while (w != v);
dcc[dcc_num].pb(u);
++dcc_num;
}
}
else if (v != p)
{
low[u] = min(low[u], dep[v]);
}
}
}
void ndfs(int u, int p, int d)
{
par[u] = p, dep[u] = d;
for (int v : nG[u])
{
if (v != p)
ndfs(v, u, d + 1);
}
}
void upd(int &res, int u)
{
if (u < dcc_num)
return;
u -= dcc_num;
if (res == -1 || res > u)
res = u;
}
int get(int u, int v)
{
int res = -1;
if (dep[u] < dep[v])
swap(u, v);
while (dep[u] > dep[v])
{
u = par[u];
if (u != v)
upd(res, u);
}
if (u == v)
return res;
while (u != v)
{
u = par[u], v = par[v];
upd(res, u), upd(res, v);
}
return res;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N;
for (int u, v;;)
{
cin >> u >> v;
if (u == 0 && v == 0)
break;
--u, --v;
G[u].pb(v), G[v].pb(u);
}
int s, t;
cin >> s >> t;
--s, --t;
int res = -1;
memset(dep, -1, sizeof(dep));
memset(idx, -1, sizeof(idx));
for (int i = 0; i < N; ++i)
{
if (dep[i] != -1)
continue;
vs.clear();
top = 0, rt = i;
dcc_num = 0;
dfs(i, -1, 0);
if (!vs.count(s) || !vs.count(t))
continue;
for (int j = 0; j < dcc_num; ++j)
{
for (int u : dcc[j])
{
if (cut[u])
nG[j].pb(dcc_num + u), nG[dcc_num + u].pb(j);
else
idx[u] = j;
}
}
int u = cut[s] ? s + dcc_num : idx[s];
int v = cut[t] ? t + dcc_num : idx[t];
ndfs(0, -1, 0);
res = get(u, v);
break;
}
if (res == -1)
cout << "No solution\n";
else
cout << res + 1 << '\n';
return 0;
}
|