ICode9

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

战略游戏[SDOI2018]

2021-01-04 22:32:17  阅读:188  来源: 互联网

标签:ch 游戏 int top stk num SDOI2018 战略 sum


https://www.luogu.com.cn/problem/P4606

题解

每次是试图摧毁一个城市和它连着的所有边,发现如果摧毁的不是一个割点那么就不会有任何影响,所以先建出原图的圆方树

每次选择了若干个关键节点,建出这些关键节点在圆方树上的虚树,有一个显而易见的结论:

答案即为虚树上(包括在虚树的某条边上)所有非关键节点的圆点个数

虚树上所有的叶子节点都一定是关键节点

断掉一个非关键的圆点一定会使得它子树里的一个叶子节点和其它子树外的关键节点不再连通

所以断掉一个非关键的圆点一定满足小Q要求

这题也不需要真的把虚树建出来,预处理圆方树上每个点到根的路径上有多少圆点,查询时只需要统计虚树的每条边上有多少圆点,最后再减掉 \(|S|\) 个关键圆点即为答案

#include <bits/stdc++.h>
#define N 300005
using namespace std;

template <typename T>
inline void read(T &num) {
	T x = 0, ff = 1; char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') ff = -1;
	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
	num = x * ff; 
}
template <typename T>
void write(T num) {
	if (num < 0) putchar('-'), num = -num;
	if (num > 9) write(num/10);
	putchar(num%10+'0');
}

int ttt, n, P, m, Q, K;
int head[N], pre[N<<1], to[N<<1], sz;
int dfn[N], dfsx[N], low[N], tme, stk[N], top, pp[N]; 
vector<int> e[N];
int d[N], p[N][21], sum[N];

void init_TU() { memset(head, 0, sizeof(head)); sz = 0; }
void init_OTHERS() {
	for (int i = 1; i <= n; i++) e[i].clear();
	memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); tme = 0;
	memset(stk, 0, sizeof(stk)); top = 0; memset(dfsx, 0, sizeof(dfsx));
	memset(d, 0, sizeof(d)); memset(p, 0, sizeof(p)); memset(sum, 0, sizeof(sum));
}
void initALL() { init_TU(); init_OTHERS(); }
void addedge(int u, int v) {
	pre[++sz] = head[u]; head[u] = sz; to[sz] = v;
	pre[++sz] = head[v]; head[v] = sz; to[sz] = u;
}

void tarjan(int x) {
	dfn[x] = low[x] = ++tme; stk[++top] = x;
	for (int i = head[x]; i; i = pre[i]) {
		int y = to[i];
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
			if (low[y] == dfn[x]) {
				int z = 0; ++n;
				do {
					z = stk[top--];
					e[z].push_back(n); e[n].push_back(z);
				} while (z != y);
				e[x].push_back(n); e[n].push_back(x);
			}
		} else low[x] = min(low[x], dfn[y]);
	}
}

void dfs(int x, int fa) {
	dfsx[x] = ++tme; sum[x] = (x <= P) + sum[fa];
	for (int l = 1; (1 << l) <= n; l++) p[x][l] = p[p[x][l-1]][l-1];
	for (auto y : e[x]) {
		if (y == fa) continue;
		d[y] = d[x] + 1; p[y][0] = x; dfs(y, x);
	}
}
inline int LCA(int x, int y) {
	if (d[x] < d[y]) swap(x, y);
	for (int i = 20; ~i; i--) if (d[x]-(1<<i)>=d[y]) x = p[x][i];
	if (x == y) return x;
	for (int i = 20; ~i; i--) if (p[x][i] != p[y][i]) x = p[x][i], y = p[y][i];
	return p[x][0];
} 
bool cmp(int x, int y) { return dfsx[x] < dfsx[y]; }
int solve() {
	top = 0; int ans = 0;
	for (int i = 1; i <= K; i++) {
		if (!top) { stk[++top] = pp[i]; continue; }
		int lca = LCA(stk[top], pp[i]);
		while (top > 1 && dfsx[stk[top-1]] >= dfsx[lca]) {
			ans += sum[stk[top]]-sum[stk[top-1]]; --top;
		} 
		if (stk[top] != lca) {
			ans += sum[stk[top]]-sum[lca]; stk[top] = lca;
		}
		stk[++top] = pp[i];
	}
	while (top > 1) { 
		ans += sum[stk[top]]-sum[stk[top-1]]; --top; 
	}
	ans += (stk[top] <= P);
	return ans - K;
}
int main() {
	read(ttt);
	while (ttt--) {
		initALL();
		read(n); read(m); P = n;
		for (int i = 1, u, v; i <= m; i++) {
			read(u); read(v); addedge(u, v);
		}
		tarjan(1); tme = 0; dfs(1, 0);
		read(Q);
		for (int kk = 1; kk <= Q; kk++) {
			read(K); for (int i = 1; i <= K; i++) read(pp[i]);
			sort(pp + 1, pp + K + 1, cmp);
			write(solve()); puts("");
		}
	}
	return 0;
}

标签:ch,游戏,int,top,stk,num,SDOI2018,战略,sum
来源: https://www.cnblogs.com/ak-dream/p/AK_DREAM120.html

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

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

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

ICode9版权所有