Solution -「SDOI 2018」「洛谷 P4606」战略游戏
\(\mathcal{Description}\)
Link.
给定一个 \(n\) 个点 \(m\) 条边的无向连通图,\(q\) 次询问,每次给出一个点集 \(s\),求至少在原图中删去多少个点,使得 \(s\) 中存在两点不连通。多组数据。
每组数据 \(n,q\le10^5\),\(m,\sum|s|\le2\times10^5\)。
\(\mathcal{Solution}\)
看到 \(\sum|s|\) 的限制,不难联想到虚树或者其它与 DFN 相关的算法。
所以,先建出圆方树,并处理好 DFN,LCA 的一系列信息。考虑到答案就是 \(s\) 中的点在树上构成的连通块中不在 \(s\) 集合里的圆点个数,可以求一个树上前缀和:\(sum_u\) 表示从 \(u\) 到根路径上的圆点个数。处理询问时,先将 \(s\) 按 DFN 从小到大排序,两两 LCA 计算贡献(\(s_1\) 和 \(s_{|s|}\) 也要算一次),最后除以 \(2\),得到 \(cnt\)。不过整个连通块的根(\(\operatorname{LCA}(s_1,s_{|s|})\))这个点的贡献被遗漏了,所以要再加上这个点单独的贡献。最终答案就是 \(cnt-|s|\)。
复杂度 \(\mathcal O(T(n\log n+\sum|s|\log\sum|s|))\)。
\(\mathcal{Code}\)
就是练练码力的一道题嘛 qwq。
#include <queue>
#include <cstdio>
#include <algorithm>
#define adj( g, u, v ) \
for ( int eid = g.head[u], v; v = g.to[eid], eid; eid = g.nxt[eid] )
const int MAXN = 2e5, MAXM = 4e5;
int n, m, q, snode;
int dfc, top, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5];
int lg[MAXN * 2 + 5], dep[MAXN + 5], st[MAXN * 2 + 5][20], sum[MAXN + 5];
struct Graph {
int ecnt, head[MAXN + 5], to[MAXM + 5], nxt[MAXM + 5];
inline void link ( const int s, const int t ) {
to[++ ecnt] = t, nxt[ecnt] = head[s];
head[s] = ecnt;
}
inline void add ( const int u, const int v ) {
link ( u, v ), link ( v, u );
}
inline void clear () {
ecnt = 0;
for ( int i = 1; i <= n << 1; ++ i ) head[i] = 0;
}
} src, tre;
inline int rint () {
int x = 0; char s = getchar ();
for ( ; s < '0' || '9' < s; s = getchar () );
for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
return x;
}
inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; }
inline void clear () {
src.clear (), tre.clear ();
dfc = top = snode = 0;
for ( int i = 1; i <= n << 1; ++ i ) dfn[i] = low[i] = 0;
}
inline void Tarjan ( const int u, const int f ) {
dfn[u] = low[u] = ++ dfc, stk[++ top] = u;
adj ( src, u, v ) if ( v ^ f ) {
if ( ! dfn[v] ) {
Tarjan ( v, u ), chkmin ( low[u], low[v] );
if ( low[v] >= dfn[u] ) {
tre.add ( u, ++ snode );
do tre.add ( snode, stk[top] ); while ( stk[top --] ^ v );
}
} else chkmin ( low[u], dfn[v] );
}
}
inline void initDFN ( const int u, const int f ) {
dep[st[dfn[u] = ++ dfc][0] = u] = dep[f] + 1, sum[u] = sum[f] + ( u <= n );
adj ( tre, u, v ) if ( v ^ f ) initDFN ( v, u ), st[++ dfc][0] = u;
}
inline void initST () {
for ( int i = 2; i <= n << 2; ++ i ) lg[i] = lg[i >> 1] + 1;
for ( int j = 1; 1 << j <= dfc; ++ j ) {
for ( int i = 1; i + ( 1 << j ) - 1 <= dfc; ++ i ) {
if ( dep[st[i][j - 1]] < dep[st[i + ( 1 << j >> 1 )][j - 1]] ) st[i][j] = st[i][j - 1];
else st[i][j] = st[i + ( 1 << j >> 1 )][j - 1];
}
}
}
inline int calcLCA ( int u, int v ) {
if ( dfn[u] > dfn[v] ) u ^= v ^= u ^= v;
int k = lg[dfn[v] - dfn[u] + 1];
return dep[st[dfn[u]][k]] < dep[st[dfn[v] - ( 1 << k ) + 1][k]] ?
st[dfn[u]][k] : st[dfn[v] - ( 1 << k ) + 1][k];
}
inline void solve () {
static int cnts, s[MAXN + 5];
cnts = rint ();
for ( int i = 1; i <= cnts; ++ i ) s[i] = rint ();
std::sort ( s + 1, s + cnts + 1, []( const int a, const int b ) { return dfn[a] < dfn[b]; } );
int cnt = 0;
for ( int i = 1; i < cnts; ++ i ) {
int u = s[i], v = s[i + 1], t = calcLCA ( u, v );
cnt += sum[u] + sum[v] - 2 * sum[t];
}
int u = s[1], v = s[cnts], t = calcLCA ( u, v );
cnt += sum[u] + sum[v] - 2 * sum[t];
cnt /= 2, cnt += ( t <= n ) - cnts;
printf ( "%d\n", cnt );
}
int main () {
for ( int T = rint (); T --; clear () ) {
n = snode = rint (), m = rint ();
for ( int i = 1, u, v; i <= m; ++ i ) {
u = rint (), v = rint ();
src.add ( u, v );
}
Tarjan ( 1, 0 ), dfc = 0;
initDFN ( 1, 0 ), initST ();
for ( q = rint (); q --; ) solve ();
}
return 0;
}
Solution -「SDOI 2018」「洛谷 P4606」战略游戏的更多相关文章
- 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】
题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...
- 洛谷P4606 [SDOI2018]战略游戏 [广义圆方树]
传送门 思路 先考虑两点如何使他们不连通. 显然路径上所有的割点都满足条件. 多个点呢?也是这样的. 于是可以想到圆方树.一个点集的答案就是它的虚树里圆点个数减去点集大小. 可以把点按dfs序排序,然 ...
- 【洛谷P2016】战略游戏
题面 题解 树形\(dp\)(最大独立集) 设\(f_{i,0/1}\)表示\(dp\)到第\(i\)个点,在这个点放了(没放)士兵的最小花费 直接转移即可. 代码 #include<cstdi ...
- 洛谷4606 SDOI2018战略游戏(圆方树+虚树)
QWQ深受其害 当时在现场是真的绝望...... 现在再重新来看这个题 QWQ 根据题目所说,我们可以发现,对于每一个集合中的节点,我们实际上就是要求两两路径上的割点的数目 考虑到又是关于点双的题目, ...
- 「区间DP」「洛谷P1043」数字游戏
「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...
- 洛谷P1118 数字三角形游戏
洛谷1118 数字三角形游戏 题目描述 有这么一个游戏: 写出一个1-N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直 ...
- 洛谷P1274-魔术数字游戏
Problem 洛谷P1274-魔术数字游戏 Accept: 118 Submit: 243Time Limit: 1000 mSec Memory Limit : 128MB Probl ...
- 洛谷P1288 取数游戏II(博弈)
洛谷P1288 取数游戏II 先手必胜的条件需要满足如下中至少 \(1\) 条: 从初始位置向左走到第一个 \(0\) 的位置,经过边的数目为偶数(包含 \(0\) 这条边). 从初始位置向右走到第一 ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
随机推荐
- Hive分析统计离线日志信息
关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...
- 使用.NET 6开发TodoList应用(23)——实现请求限流
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 Rate Limiting允许保护我们的API服务免受过多请求的连接导致的性能下降,如果请求次数超过了限制,API服务端将会拒 ...
- Java 将PDF转为PDF/A
通过将PDF格式转换为PDF/A格式,可保护文档布局.格式.字体.大小等不受更改,从而实现文档安全保护的目的,同时又能保证文档可读.可访问.本篇文章,将通过Java后端程序代码展示如何将PDF转为符合 ...
- Android官方文档翻译 十 2.3Styling the Action Bar
Styling the Action Bar 设计菜单栏的样式 This lesson teaches you to 这节课教给你 Use an Android Theme 使用一个Android主题 ...
- 什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?
1. XSS(Cross Site Script,跨站脚本攻击) 是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式. 1.1跨站脚本攻击分有两种形式: 反射型攻击(诱使用户点 ...
- 508. Most Frequent Subtree Sum
Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a ...
- golang中的GOPATH使用和简单项目配置
GOPATH 是 Go 语言的工作目录,他的值可以是一个目录路径,也可以是多个目录路径,每个目录都代表 go 语言的一个工作区. 我们开发 Golang 项目时,需要依赖一些别的代码包,这些包的存放路 ...
- AOP-基本概念
AOP(概念) 1,什么是AOP (1)面向切面(方面)编程 :利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. (2)通 ...
- Telegra.ph | 简洁的文章发布平台
https://telegra.ph 自由 Telegraph 并不强调内容管理方这一概念,真正做到了「人人都是媒体」.通过 Telegraph 发布的文章,理论上来说不会存在删除的危险,并且由于会产 ...
- 在build中配置resources, 来防止我们资源导出失败问题
<!--在build中配置resources, 来防止我们资源导出失败问题--> <build> <resources> <resource> < ...