P4606 [SDOI2018] 战略游戏

Sol

还挺好玩的一个题(?),但是比较难写。

注意到两个点的做法就是这两个点圆方树上的路径上的圆点数量减去 \(2\)

那么多个点就是按照 dfn 排序后相邻的点(还有第一个和最后一个之间)做类似于两个点统计答案的方式,然后因为这玩意需要路径的和,这里我写了树剖,所以有点长。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define eb emplace_back
#define pf push_front
#define desktop "C:\\Users\\MPC\\Desktop\\"
#define IOS ios :: sync_with_stdio (false),cin.tie (0),cout.tie (0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int,int> PII;
const int dx[] = {1,0,-1,0},dy[] = {0,-1,0,1};
template <typename T1,typename T2> bool tomax (T1 &x,T2 y) {
	if (y > x) return x = y,true;
	return false;
}
template <typename T1,typename T2> bool tomin (T1 &x,T2 y) {
	if (y < x) return x = y,true;
	return false;
}
LL power (LL a,LL b,LL p) {
	LL ans = 1;
	while (b) {
		if (b & 1) ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}
int fastio = (IOS,0);
#define endl '\n'
#define puts(s) cout << (s) << endl
const int N = 1000010,MAX_LOG = 20;
int n,m,q;
vector <int> g[N],g2[N];
int dfn[N],low[N],timestamp;
int stk[N];
int top;
int s[N];
int idx;
int f[N][MAX_LOG];
int dep[N];
int dis[N];
int a[N];
void tarjan (int u,int fa) {
	dfn[u] = low[u] = ++timestamp;
	stk[++top] = u;
	for (int v : g[u]) {
		if (v == fa) continue;
		if (!dfn[v]) {
			tarjan (v,u);
			tomin (low[u],low[v]);
			if (low[v] >= dfn[u]) {
				idx++;
				g2[idx].pb (u),g2[u].pb (idx);
				do g2[idx].pb (stk[top]),g2[stk[top]].pb (idx);
				while (stk[top--] != v) ;
			}
		}
		else tomin (low[u],dfn[v]);
	}
}
void DFS (int u,int fa) {
	dfn[u] = ++timestamp;
	dep[u] = dep[fa] + 1;
	dis[u] = dis[fa] + (u <= n);
	for (int v : g2[u]) {
		if (v == fa) continue;
		f[v][0] = u;
		for (int i = 1;i < MAX_LOG;i++) f[v][i] = f[f[v][i - 1]][i - 1];
		DFS (v,u);
	}
}
int get_LCA (int a,int b) {
	if (dep[a] < dep[b]) swap (a,b);
	for (int i = MAX_LOG - 1;i >= 0;i--) {
		if (dep[f[a][i]] >= dep[b]) a = f[a][i];
	}
	if (a == b) return a;
	for (int i = MAX_LOG - 1;i >= 0;i--) {
		if (f[a][i] == f[b][i]) continue;
		a = f[a][i],b = f[b][i];
	}
	return f[a][0];
}
int get_dis (int a,int b) {
	return dis[a] + dis[b] - 2 * dis[get_LCA (a,b)];
}
void mian () {
	cin >> n >> m;
	for (int i = 1;i <= 2 * n;i++) g[i].clear (),g2[i].clear (),dfn[i] = 0;
	timestamp = 0;
	while (m--) {
		int a,b;
		cin >> a >> b;
		g[a].pb (b),g[b].pb (a);
	}
	idx = n;
	tarjan (1,0);
	timestamp = 0;
	DFS (1,0);
	cin >> q;
	while (q--) {
		int k;
		cin >> k;
		for (int i = 1;i <= k;i++) cin >> a[i];
		sort (a + 1,a + k + 1,[](int i,int j) {
			return dfn[i] < dfn[j];
		});
		LL ans = 0;
		for (int i = 1;i <= k;i++) ans += get_dis (a[i],a[i % k + 1]);
		ans /= 2;
		ans -= k;
		ans += (get_LCA (a[1],a[k]) <= n);
		cout << ans << endl;
	}
}
int main () {
	int T = 1;
	cin >> T;
	while (T--) mian ();
	return 0;
}
posted @ 2025-05-14 20:17  incra  阅读(15)  评论(0)    收藏  举报