Description
有一张无向图,每次给定一个集合 ,求有多少个点满足删除这个点后, 中至少有两个点不连通。
,
Solution
考虑所求就是 在圆方树上虚树的圆点数- 。
但实际并不需要把虚树求出来,考虑把一个圆点的权值放在它到父亲方点的边上,那么把 按 序排序后,答案为
这个可以画图感受一下。
注意当虚树上最浅点为圆点时,要加上它的权值。
#include <bits/stdc++.h>
using namespace std;
inline int gi()
{
char c = getchar();
while(c < '0' || c > '9') c = getchar();
int sum = 0;
while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
const int maxn = 100005;
int n, m, s[maxn];
struct edge
{
int to, next;
} e[maxn << 2];
int h[maxn << 1], tot, cnt;
inline void add(int u, int v)
{
e[++tot] = (edge) {v, h[u]}; h[u] = tot;
e[++tot] = (edge) {u, h[v]}; h[v] = tot;
}
namespace Tarjan
{
struct edge
{
int to, next;
} e[maxn << 2];
int h[maxn], tot;
inline void Add(int u, int v)
{
e[++tot] = (edge) {v, h[u]}; h[u] = tot;
e[++tot] = (edge) {u, h[v]}; h[v] = tot;
}
int dfn[maxn], low[maxn], Time, stk[maxn], top;
void dfs(int u)
{
dfn[u] = low[u] = ++Time;
stk[++top] = u;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
if (dfn[u] == low[v]) {
++cnt;
while (stk[top + 1] != v)
add(stk[top], cnt), --top;
add(cnt, u);
}
} else low[u] = min(low[u], dfn[v]);
}
}
int fa[maxn << 1], dep[maxn << 1], dis[maxn << 1], siz[maxn << 1], son[maxn << 1], top[maxn << 1], dfn[maxn << 1], low[maxn << 1], Time;
int vis[maxn << 1];
void dfs1(int u)
{
vis[u] = 1;
dep[u] = dep[fa[u]] + 1; dis[u] = dis[fa[u]] + (u <= n); siz[u] = 1; son[u] = 0;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != fa[u]) {
if (vis[v])
puts("call me"), exit(0);
fa[v] = u; dfs1(v); siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u)
{
dfn[u] = ++Time;
if (son[u]) top[son[u]] = top[u], dfs2(son[u]);
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != son[u] && v != fa[u]) top[v] = v, dfs2(v);
low[u] = Time;
}
inline int lca(int u, int v)
{
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
int main()
{
int T = gi();
while (T--) {
n = gi(); m = gi();
fill(h + 1, h + cnt + 1, 0); tot = 0;
fill(Tarjan::h + 1, Tarjan::h + n + 1, 0); Tarjan::tot = 0;
fill(Tarjan::dfn + 1, Tarjan::dfn + n + 1, 0);
for (int i = 1; i <= m; ++i) Tarjan::Add(gi(), gi());
cnt = n; Tarjan::Time = 0;
Tarjan::dfs(1); --Tarjan::top;
memset(vis + 1, 0, sizeof(vis));
dfs1(1);
Time = 0; top[1] = 1; dfs2(1);
int q = gi(), k;
while (q--) {
k = gi();
for (int i = 1; i <= k; ++i) s[i] = gi();
sort(s + 1, s + k + 1, [](const int &a, const int &b) {return dfn[a] < dfn[b];});
int ans = -2 * k;
for (int i = 1; i < k; ++i) ans += dis[s[i]] + dis[s[i + 1]] - (dis[lca(s[i], s[i + 1])] << 1);
ans += dis[s[k]] + dis[s[1]] - (dis[lca(s[k], s[1])] << 1);
if (lca(s[1], s[k]) <= n) ans += 2;
printf("%d\n", ans >> 1);
}
}
return 0;
}