MnZn虚树+圆方树做法求助
查看原帖
MnZn虚树+圆方树做法求助
503792
Svemit楼主2024/5/11 13:07

rt,计算答案的思路是分三类

  1. 在虚树上的圆点,如果子树内和子树外都有关键点,那么计入答案。

  2. 不在虚树上的圆点,如果需要计入答案那么一定会在虚树上两个点中间,计算一类点时加上 dist(u)−dist(fa)dist(u) - dist(fa)

  3. 在虚树上的圆点,有超过一个儿子的 siz >= 1,计入答案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5;

int n, m;
int tot;
vector<int> e[N], G[N], E[N];
int p[N], a[N];
int dfn[N], low[N], tim;
stack<int> stk;
int dep[N], fa[N][20], dist[N];
int dfnG[N], timG;
int siz[N], key[N];
int ans;

void tarjan(int u) {
	dfn[u] = low[u] = ++ tim;
	stk.push(u);
	for (auto v : e[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u]) {
				tot ++;
				int x;
				do {
					x = stk.top(), stk.pop();
					G[x].push_back(tot);
					G[tot].push_back(x);
				} while (x != v);
				G[u].push_back(tot);
				G[tot].push_back(u);
			}
		}
		else {
			low[u] = min(low[u], dfn[v]);
		}
	}
}

void dfs(int u, int fath) {
	dfnG[u] = ++ timG;
	dep[u] = dep[fath] + 1, dist[u] = dist[fath] + (u <= n);
	fa[u][0] = fath;
	for (int i = 1; i <= __lg(dep[u]); i ++) {
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
	}
	for (auto v : G[u]) {
		if (v == fath) continue;
		dfs(v, u);
	}
}

int lca(int u, int v) {
	if (dep[u] < dep[v]) {
		swap(u, v);
	}
	while (dep[u] != dep[v]) {
		u = fa[u][__lg(dep[u] - dep[v])];
	}
	if (u == v) {
		return u;
	} 
	for (int k = __lg(dep[u]); k >= 0; k --) {
		if (fa[u][k] != fa[v][k]) {
			u = fa[u][k], v = fa[v][k];
		}
	} 
	return fa[u][0];
}

bool cmp(int a, int b) {
	return dfnG[a] < dfnG[b];
}

void dfs_E(int u, int sum) {
	siz[u] = key[u];
	int c = 0;
	for (auto v : E[u]) {
		dfs_E(v, sum);
		siz[u] += siz[v];
		if (siz[v] >= 1) {
			c ++;
		}
	}
	for (auto v : E[u]) {
		if (siz[v] >= 1 && sum - siz[v] >= 1) {
			ans += dist[fa[v][0]] - dist[u];
		}
	}
	E[u].clear();
	if (key[u] || u > n) {
		return;
	}
	if ((sum - siz[u] >= 1 && siz[u] >= 1) || c > 1) {
		ans ++;
	}
}

void solve() {
	memset(dfn, 0, sizeof dfn);
	memset(low, 0, sizeof low);
	memset(dfnG, 0, sizeof dfnG);
	memset(dist, 0, sizeof dist);
	cin >> n >> m;
	for (int i = 1; i <= 2 * n; i ++) {
		e[i].clear(), G[i].clear(), E[i].clear();
	}

	for (int i = 1; i <= m; i ++) {
		int u, v;
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	tot = n;
	tarjan(1), dfs(1, 0);
	int q;
	cin >> q;
	while (q --) {
		int c;
		cin >> c;
		int cnt = 0;
		for (int i = 1; i <= c; i ++) {
			cin >> p[i];
			key[p[i]] = 1;
			a[++ cnt] = p[i];
		}
		a[++ cnt] = 1;
		sort(p + 1, p + 1 + c, cmp);
		for (int i = 1; i < c; i ++) {
			a[++ cnt] = lca(p[i], p[i + 1]);
		}
		sort(a + 1, a + 1 + cnt, cmp);
		cnt = unique(a + 1, a + 1 + cnt) - a - 1;
		// cout << "----------\n";
		for (int i = 1; i < cnt; i ++) {
			E[lca(a[i], a[i + 1])].push_back(a[i + 1]);
			// cout << lca(a[i], a[i + 1]) << " " << a[i + 1] << "\n";
		}
		ans = 0;
		dfs_E(1, c);
		cout << ans << "\n";
		for (int i = 1; i <= c; i ++) {
			key[p[i]] = 0;
		}
	}	
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);

	int t;
	cin >> t;

	while (t --) {
		solve();
	}

	return 0;
}
2024/5/11 13:07
加载中...