ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SDOI2018]战略游戏

2022-01-25 22:32:07  阅读:150  来源: 互联网

标签:cnt 游戏 int 战略 fa dfn low SDOI2018 dis


\(\text{Solution}\)

问题的转化,建成圆方树后,变为询问 \(S\) 在圆方树上对应的连通子图中的圆点个数减去 \(|S|\)
而根据 \(\text{SDOI2015 寻宝游戏}\) 里的一个重要结论
包含 \(S\) 的极小连通子图边权和的两倍等于将 \(S\) 里的点按 \(dfs\) 序排序后 \(dis(a_1,a_2)+dis(a_2,a_3)+...+dis(a_{n-1},a_n)+dis(a_n,a_1)\)
而在圆方树中统计圆点数量,可将圆点到其上方点的边权赋为 \(1\)
然后按结论计算后结果除以 \(2\) 相当于一棵树的若干边被计算了,一条边对应其下一个圆点
而如果最浅的 \(LCA\) 是圆点,我们还要统计它
注意多组数据,倍增求 \(LCA\) 的 \(fa\) 数组要清零!!

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#define IN inline
#define RE register
using namespace std;

const int N = 2e5 + 5;
int T, n, m, q, cnt, a[N], h1[N], h2[N], tot1, tot2, low[N], dfn[N], dfc, top, stk[N], fa[N][21], dis[N], dep[N];
struct edge{int to, nxt;}e1[N * 4], e2[N * 4];
IN void add1(int x, int y){e1[++tot1] = edge{y, h1[x]}, h1[x] = tot1;}
IN void add2(int x, int y){e2[++tot2] = edge{y, h2[x]}, h2[x] = tot2;}
IN bool cmp(int x, int y){return dfn[x] < dfn[y];}

void Tarjan(int x)
{
	dfn[x] = low[x] = ++dfc, stk[++top] = x;
	for(RE int i = h1[x]; i; i = e1[i].nxt)
	{
		int v = e1[i].to;
		if (!dfn[v])
		{
			Tarjan(v), low[x] = min(low[x], low[v]);
			if (dfn[x] == low[v])
			{
				++cnt, add2(cnt, x), add2(x, cnt);
				for(RE int u = 0; u ^ v; --top) u = stk[top], add2(cnt, u), add2(u, cnt);
			}
		}
		else low[x] = min(low[x], dfn[v]);
	}
}

void Dfs(int x)
{
	for(RE int i = 1; i < 19; i++) if (fa[x][i - 1]) fa[x][i] = fa[fa[x][i - 1]][i - 1]; else break;
	dis[x] += (x <= n), dfn[x] = ++dfc;
	for(RE int i = h2[x]; i; i = e2[i].nxt)
	{
		int v = e2[i].to;
		if (v == fa[x][0]) continue;
		fa[v][0] = x, dis[v] += dis[x], dep[v] = dep[x] + 1, Dfs(v);
	}
}

IN int LCA(int x, int y)
{
	if (dep[x] < dep[y]) swap(x, y);
	int deep = dep[x] - dep[y];
	for(RE int i = 0; i < 19; i++) if ((deep >> i) & 1) x = fa[x][i];
	if (x == y) return x;
	for(RE int i = 18; i >= 0; i--) if (fa[x][i] ^ fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}
IN int Query(int x, int y){return dis[x] + dis[y] - dis[LCA(x, y)] * 2;}

IN void read(int &x)
{
	x = 0; int f = 1; char ch = getchar();
	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
	x *= f;
}

int main()
{
	read(T);
	for(; T; --T)
	{
		read(n), read(m), cnt = n, top = dfc = tot1 = tot2 = 0;
		memset(h1, 0, sizeof h1), memset(h2, 0, sizeof h2), memset(dis, 0, sizeof dis);
		memset(fa, 0, sizeof fa), memset(dfn, 0, sizeof dfn);
		for(RE int i = 1, u, v; i <= m; i++) read(u), read(v), add1(u, v), add1(v, u);
		Tarjan(1), dfc = 0, Dfs(1), read(q);
		for(RE int num; q; --q)
		{
			read(num); for(RE int i = 1; i <= num; i++) read(a[i]);
			sort(a + 1, a + num + 1, cmp); int ans = -2 * num;
			for(RE int i = 1; i <= num; i++) ans += Query(a[i], a[i % num + 1]);
			if (LCA(a[1], a[num]) <= n) ans += 2;
			printf("%d\n", ans >> 1);
		}
	}
}

标签:cnt,游戏,int,战略,fa,dfn,low,SDOI2018,dis
来源: https://www.cnblogs.com/leiyuanze/p/15844695.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有