[bzoj5329][Sdoi2018]战略游戏

题目大意:多组数据,每组数据给一张图,多组询问,每个询问给一个点集,要求删除一个点,使得至少点集中的两个点互不连通,输出方案数

题解:圆方树,发现使得两个点不连通的方案数就是它们路径上的原点个数。如何处理重复?可以按圆方树的$dfn$序排序,相邻两点求一下贡献,这样贡献就被重复计算了两次,除去$k$个询问点就行了。还有每次计算中$lca$没有被统计,发现排序后第一个点和最后一个点的$lca$一定是深度最浅的,所以只有这个点没有被统计答案,加上即可

卡点:1.圆方树$dfn$数组没赋值

2.$LCA$的$log$太小

C++ Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 200010
#define maxm 200010
int Tim, n, m, LCA;
inline int min(int a, int b) {return a < b ? a : b;}
inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}
struct Tree {
	#define root 1
	#define fa(u) dad[u][0]
	#define M 18
	int head[maxn], cnt;
	struct Edge {
		int to, nxt;
	} e[maxm << 1];
	inline void addE(int a, int b) {e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;}
	inline void add(int a, int b) {
		addE(a, b);
		addE(b, a);
	}

	int dad[maxn][M], dep[maxn], sz[maxn];
	int dfn[maxn], idx;
	void dfs(int u = root) {
		dfn[u] = ++idx;
		for (int i = 1; i < M; i++) dad[u][i] = dad[dad[u][i - 1]][i - 1];
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (v != fa(u)) {
				sz[v] = sz[u] + int(v <= n);
				dep[v] = dep[u] + 1;
				fa(v) = u;
				dfs(v);
			}
		}
	}
	inline int LCA(int x, int y) {
		if (dep[x] < dep[y]) swap(x, y);
		for (int i = dep[x] - dep[y]; i; i &= i - 1) x = dad[x][__builtin_ctz(i)];
		if (x == y) return x;
		for (int i = M - 1; ~i; i--) if (dad[x][i] != dad[y][i]) x = dad[x][i], y = dad[y][i];
		return fa(x);
	}

	inline int len(int x, int y) {
		return sz[x] + sz[y] - (sz[::LCA = LCA(x, y)] << 1);
	}

	inline void init() {
		memset(head, 0, sizeof head); cnt = 0;
		memset(dfn, 0, sizeof dfn); idx = 0;
		sz[root] = 0;
	}
	#undef root
	#undef fa
	#undef M
} T;

struct Graph {
	#define root 1
	int head[maxn], cnt;
	struct Edge {
		int to, nxt;
	} e[maxm << 1];
	inline void addE(int a, int b) {e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;}
	inline void add(int a, int b) {
		addE(a, b);
		addE(b, a);
	}

	int DFN[maxn], low[maxn], idx, CNT;
	int S[maxn], top, tmp;
	void tarjan(int u = root) {
		DFN[u] = low[u] = ++idx;
		S[++top] = u;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (!DFN[v]) {
				tarjan(v);
				low[u] = min(low[u], low[v]);
				if (low[v] >= DFN[u]) {
					CNT++;
					T.add(CNT, u);
					do {
						T.add(CNT, tmp = S[top--]);
					} while (tmp != v);
				}
			} else low[u] = min(low[u], DFN[v]);
		}
	}

	inline void init(int n) {
		memset(head, 0, sizeof head); cnt = 0;
		memset(DFN, 0, sizeof DFN); idx = 0;
		CNT = n;
	}
	#undef root
} G;

#define Online_Judge
#define read() R::READ()
#include <cctype>
namespace R {
    int x;
    #ifdef Online_Judge
    char *ch, op[1 << 26];
    inline void init() {
        fread(ch = op, 1, 1 << 26, stdin);
    }
    inline int READ() {
        while (isspace(*ch)) ch++;
        for (x = *ch & 15, ch++; isdigit(*ch); ch++) x = x * 10 + (*ch & 15);
        return x;
    }
    #else
    char ch;
    inline int READ() {
        ch = getchar();
        while (isspace(ch)) ch = getchar();
        for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15);
        return x;
    }
    #endif
}

int s[maxn];
inline bool cmp(int a, int b) {return T.dfn[a] < T.dfn[b];}
int main() {
    #ifdef Online_Judge
    R::init();
    #endif
	Tim = read();
	while (Tim --> 0) {
		G.init(n = read()), T.init();
		for (int i = m = read(); i; i--) G.add(read(), read());
		G.tarjan();
		T.dfs();
		int Q = read();
		while (Q --> 0) {
			int k = read(), ans = 0;
			for (int i = 0; i < k; i++) s[i] = read();
			std::sort(s, s + k, cmp);
			s[k] = s[0];
			for (int i = 0; i < k; i++) ans += T.len(s[i], s[i + 1]);
			printf("%d\n", (ans >> 1) - k + int(LCA <= n));
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9650984.html

时间: 2024-07-31 04:25:30

[bzoj5329][Sdoi2018]战略游戏的相关文章

bzoj 5329 [SDOI2018] 战略游戏

bzoj 5329 [SDOI2018] 战略游戏 Link Solution 很容易想到虚树 然后发现是一个图... 现学圆方树,套上去,做完了(模板题?) 就是直接上广义圆方树先把这玩意转换成一棵树,然后对当前询问建立虚树,断掉虚树里任何一个点都合法(包括不出现的点,指那些在某个点和其虚树上父亲之间的点),统计一下即可 Code // Copyright lzt #include<stdio.h> #include<cstring> #include<cstdlib>

[SDOI2018]战略游戏 圆方树,树链剖分

[SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中的圆点个数减去\(S\).问题变成了怎样求这样的连通块中的圆点个数,直接给结论吧:先搞出树的dfs序,把询问的点按dfs序从小到大排一遍序,每次把答案加上第\(i\)和第\(i + 1\)个点之间的圆点个数,但是不算lca,再加上第\(1\)个和第\(S\)个点之间的圆点个数,然后除以二就得到了这个

[SDOI2018]战略游戏

题目描述 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到 任意其他城市.现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这 个城市的道路.只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不 能走到v,那么小Q就能赢下这一局游戏. 小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领

Facebook开源游戏平台ELF: 一个用于实时战略游戏研究的轻量级平台

ELF是一个用于游戏研究的应用广泛的(Extensive).轻量级的(Lightweight).灵活的(Flexible)平台,特别适用于实时战略(RTS)游戏.在C++方面,ELF采用C++线程来并发运行多个游戏.在Python方面,ELF可以一次性返回一批游戏状态,使其对现代RL(强化学习)非常友好.另一方面,在其他平台(例如OpenAI Gym)中,一个Python接口只能包含一个游戏实例.这使得游戏的并发运行有点复杂,而这又是许多现代强化学习算法的要求. 对于RTS游戏的研究,ELF配备

战略游戏

题意/Description: Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题.他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路.注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到.  请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵. 读入/Input:    输入文件中数据表示一棵树,描述如下: 第一行 N,表示树中结点的数目. 第二行至第N+1行,每行描述每个

bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分

[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军

【BZOJ3924】幻想乡战略游戏(动态点分治)

[BZOJ3924]幻想乡战略游戏(动态点分治) 题面 权限题...(穷死我了) 洛谷 题解 考虑不修改 发现一个贪心的做法 假设当前放在当前位置 如果它有一个子树的兵的总数大于总数的一半 那么,放到那个子树的根节点上一定最优 那么,现在是动态修改 考虑动态点分治 在每个点上维护子树的兵的总数 子树到上一层父亲节点 向上走产生的贡献的总和 以及接收到子节点的贡献的总和 那么,就可以计算当前点产生的贡献 于是,从分治树根开始向下贪心即可 #include<iostream> #include&l

『战略游戏 最大利润 树形DP』

通过两道简单的例题,我们来重新认识树形DP. 战略游戏(luoguP1026) Description Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题.他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路.注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到. 请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵. Input Format 输入文件中数据表示一棵树,描述如下

luoguP2016 战略游戏

题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题.他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路.注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到. 请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵. 输入格式 输入文件中数据表示一棵树,描述如下: 第一行 N,表示树中结点的数目. 第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面